VectorDrawable.java revision 16c1bd5db8f4f18e1eee8b19006bba5f06a88123
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
17b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viveretteimport android.content.res.ColorStateList;
18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources;
19abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme;
204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray;
21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas;
222af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghuiimport android.graphics.Color;
23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter;
24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix;
25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint;
26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path;
27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure;
28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat;
29b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viveretteimport android.graphics.PorterDuffColorFilter;
30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect;
31abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region;
32b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viveretteimport android.graphics.PorterDuff.Mode;
33e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghuiimport android.util.ArrayMap;
34abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet;
35abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log;
364b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport android.util.Xml;
37abb7d134c02ac60091108c491dafb00877093170John Hoford
38abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R;
39abb7d134c02ac60091108c491dafb00877093170John Hoford
40abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser;
41abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException;
424b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport org.xmlpull.v1.XmlPullParserFactory;
43abb7d134c02ac60091108c491dafb00877093170John Hoford
44abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException;
45abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList;
46abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays;
474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghuiimport java.util.Stack;
484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
49abb7d134c02ac60091108c491dafb00877093170John Hoford/**
50d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be
51d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code>&lt;vector></code> element.
52abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
5346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The vector drawable has the following elements:
54abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
55abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
56177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
57e3c45e7a6b2a7d2176aa46ee482e299b54feeb9fztenghui * <dd>Used to defined a vector drawable</dd>
58abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
59abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
60d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:width</code> and <code>android:height</code></dd>
61abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
63d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * The size is defined using the attributes <code>android:viewportHeight</code>
64d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:viewportWidth</code></dd>
656d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dt><code>&lt;group></code></dt>
66452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>Defines a group of paths or subgroups, plus transformation information.
67452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * The transformations are defined in the same coordinates as the viewport.
68452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * And the transformations are applied in the order of scale, rotate then translate. </dd>
69452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:rotation</code>
70452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The degrees of rotation of the group.</dd></dt>
71452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:pivotX</code>
72452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The X coordinate of the pivot for the scale and rotation of the group</dd></dt>
73452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:pivotY</code>
74452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The Y coordinate of the pivot for the scale and rotation of the group</dd></dt>
75452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:scaleX</code>
76452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The amount of scale on the X Coordinate</dd></dt>
77452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:scaleY</code>
78452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The amount of scale on the Y coordinate</dd></dt>
79452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:translateX</code>
80452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The amount of translation on the X coordinate</dd></dt>
81452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dt><code>android:translateY</code>
82452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui * <dd>The amount of translation on the Y coordinate</dd></dt>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
846d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines paths to be drawn.
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
8946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines path string. This is using exactly same format as "d" attribute
9046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * in the SVG's path data</dd></dt>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
93abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
94d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd>
95d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
105abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
106abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
107d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end)
108d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt>
109abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
110abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
111abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
112abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
113abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
114abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
115abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
116abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
117abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
118abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
119abb7d134c02ac60091108c491dafb00877093170John Hoford */
120abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
123abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
124abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
1256d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui    private static final String SHAPE_GROUP = "group";
126abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
127abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
128abb7d134c02ac60091108c491dafb00877093170John Hoford
129abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
130abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
131abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
133abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
134abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
135abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1374d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui    private static final boolean DBG_VECTOR_DRAWABLE = false;
1384d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
1394b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1404b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
141e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
142e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
143b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    private PorterDuffColorFilter mTintFilter;
144b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
145abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
147abb7d134c02ac60091108c491dafb00877093170John Hoford    }
148abb7d134c02ac60091108c491dafb00877093170John Hoford
1499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
15016c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui        if (theme != null && state.canApplyTheme()) {
15116c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui            // If we need to apply a theme, implicitly mutate.
15216c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui            mVectorState = new VectorDrawableState(state);
1539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
15416c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui        } else {
15516c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui            mVectorState = state;
1569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
157b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
158b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
159b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
160abb7d134c02ac60091108c491dafb00877093170John Hoford    }
161abb7d134c02ac60091108c491dafb00877093170John Hoford
162e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    Object getTargetByName(String name) {
163e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return mVGTargetsMap.get(name);
164e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
165e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
166abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
167abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
168abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
169abb7d134c02ac60091108c491dafb00877093170John Hoford    }
170abb7d134c02ac60091108c491dafb00877093170John Hoford
1714554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette    @Override
172abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
1734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
1744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
1754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
176ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
1774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
178abb7d134c02ac60091108c491dafb00877093170John Hoford    }
179abb7d134c02ac60091108c491dafb00877093170John Hoford
180abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
181e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    public int getAlpha() {
182e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return mVectorState.mVPathRenderer.getRootAlpha();
183e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
184e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
185e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    @Override
186abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
1872af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
1882af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            mVectorState.mVPathRenderer.setRootAlpha(alpha);
189abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
190abb7d134c02ac60091108c491dafb00877093170John Hoford        }
191abb7d134c02ac60091108c491dafb00877093170John Hoford    }
192abb7d134c02ac60091108c491dafb00877093170John Hoford
193abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
194abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
195b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final VectorDrawableState state = mVectorState;
196b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (colorFilter != null) {
197b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            // Color filter overrides tint.
198b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = null;
199b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        } else if (state.mTint != null && state.mTintMode != null) {
200b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            // Restore the tint filter, if we need one.
201b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT);
202b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
203b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            colorFilter = mTintFilter;
204b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        }
205b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
206b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        state.mVPathRenderer.setColorFilter(colorFilter);
207fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        invalidateSelf();
208abb7d134c02ac60091108c491dafb00877093170John Hoford    }
209abb7d134c02ac60091108c491dafb00877093170John Hoford
210abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
211b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    public void setTint(ColorStateList tint, Mode tintMode) {
212b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final VectorDrawableState state = mVectorState;
213b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (state.mTint != tint || state.mTintMode != tintMode) {
214b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            state.mTint = tint;
215b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            state.mTintMode = tintMode;
216b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
217b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
218b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
219b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            invalidateSelf();
220b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        }
221b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    }
222b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
223b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    @Override
224b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    protected boolean onStateChange(int[] stateSet) {
225b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final VectorDrawableState state = mVectorState;
226b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (state.mTint != null && state.mTintMode != null) {
227b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
228b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
229b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            return true;
230b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        }
231b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        return false;
232b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    }
233b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
234b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    @Override
235abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
236abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
237abb7d134c02ac60091108c491dafb00877093170John Hoford    }
238abb7d134c02ac60091108c491dafb00877093170John Hoford
239abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
240d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * Sets padding for this shape, defined by a Rect object. Define the padding
241d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * in the Rect object as: left, top, right, bottom.
242abb7d134c02ac60091108c491dafb00877093170John Hoford     */
243abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
244abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
245abb7d134c02ac60091108c491dafb00877093170John Hoford    }
246abb7d134c02ac60091108c491dafb00877093170John Hoford
247abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
248abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
249abb7d134c02ac60091108c491dafb00877093170John Hoford     *
250abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
251abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
252abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
253abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
254abb7d134c02ac60091108c491dafb00877093170John Hoford     */
255abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
256abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
257abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
258abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
259abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
260abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
261abb7d134c02ac60091108c491dafb00877093170John Hoford            }
262abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
263abb7d134c02ac60091108c491dafb00877093170John Hoford        }
264abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
265abb7d134c02ac60091108c491dafb00877093170John Hoford    }
266abb7d134c02ac60091108c491dafb00877093170John Hoford
267abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
268abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
269ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseWidth;
270abb7d134c02ac60091108c491dafb00877093170John Hoford    }
271abb7d134c02ac60091108c491dafb00877093170John Hoford
272abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
273abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
274ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseHeight;
275abb7d134c02ac60091108c491dafb00877093170John Hoford    }
276abb7d134c02ac60091108c491dafb00877093170John Hoford
277abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
278abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
279abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
280abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
281abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
282abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
283abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
284abb7d134c02ac60091108c491dafb00877093170John Hoford        }
285abb7d134c02ac60091108c491dafb00877093170John Hoford    }
286abb7d134c02ac60091108c491dafb00877093170John Hoford
287abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
288abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
289abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
290ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
291ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        setPathRenderer(p);
292abb7d134c02ac60091108c491dafb00877093170John Hoford    }
293abb7d134c02ac60091108c491dafb00877093170John Hoford
2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
2969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
2979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
3009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
3019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
3029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
304ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer path = state.mVPathRenderer;
3059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
3079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
3089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3104b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    /** @hide */
3114b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    public static VectorDrawable create(Resources resources, int rid) {
3124b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        try {
3134b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParser xpp = resources.getXml(rid);
3144b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final AttributeSet attrs = Xml.asAttributeSet(xpp);
3154b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
3164b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            factory.setNamespaceAware(true);
3174b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
3184b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final VectorDrawable drawable = new VectorDrawable();
3194b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.inflate(resources, xpp, attrs);
3204b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
3214b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            return drawable;
3224b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (XmlPullParserException e) {
3234b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
3244b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (IOException e) {
3254b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
3264b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        }
3274b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        return null;
3284b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    }
3294b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
3302af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui    private static int applyAlpha(int color, float alpha) {
3312af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        int alphaBytes = Color.alpha(color);
3322af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        color &= 0x00FFFFFF;
3332af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        color |= ((int) (alphaBytes * alpha)) << 24;
3342af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        return color;
3352af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui    }
3362af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui
337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
3389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
339ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer pathRenderer = new VPathRenderer();
3409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
341abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
342abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
3436d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        boolean noGroupTag = true;
344abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
3459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Use a stack to help to build the group tree.
3474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // The top of the stack is always the current group.
3484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        final Stack<VGroup> groupStack = new Stack<VGroup>();
3494d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        groupStack.push(pathRenderer.mRootGroup);
350abb7d134c02ac60091108c491dafb00877093170John Hoford
351abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
352abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
353abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
3549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
3554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final VGroup currentGroup = groupStack.peek();
3564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
357abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
3589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
3599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
3609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
361e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    if (path.getPathName() != null) {
362e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                        mVGTargetsMap.put(path.getPathName(), path);
363e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    }
364abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
365abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
366ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseSize(res, attrs);
367abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
368abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
369ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseViewport(res, attrs);
370abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
3716d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                } else if (SHAPE_GROUP.equals(tagName)) {
3724d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    VGroup newChildGroup = new VGroup();
3734d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    newChildGroup.inflate(res, attrs, theme);
3744d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    currentGroup.mChildGroupList.add(newChildGroup);
3754d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    groupStack.push(newChildGroup);
376e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    if (newChildGroup.getGroupName() != null) {
377e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                        mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
378e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    }
3796d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    noGroupTag = false;
380abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            } else if (eventType == XmlPullParser.END_TAG) {
3824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final String tagName = parser.getName();
3834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (SHAPE_GROUP.equals(tagName)) {
3844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    groupStack.pop();
3854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                }
386abb7d134c02ac60091108c491dafb00877093170John Hoford            }
387abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
388abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3904d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Print the tree out for debug.
3914d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        if (DBG_VECTOR_DRAWABLE) {
3924d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            printGroupTree(pathRenderer.mRootGroup, 0);
3936d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        }
3946d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
39546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        if (noSizeTag || noViewportTag || noPathTag) {
3969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
3979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
398abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
3999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
400abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
402d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noViewportTag) {
403d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
404abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
405abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
407abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
409d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noPathTag) {
410d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
411abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
412abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
414abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
417abb7d134c02ac60091108c491dafb00877093170John Hoford        }
4189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
419ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return pathRenderer;
420abb7d134c02ac60091108c491dafb00877093170John Hoford    }
421abb7d134c02ac60091108c491dafb00877093170John Hoford
4224d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui    private void printGroupTree(VGroup currentGroup, int level) {
4234d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        String indent = "";
4244d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        for (int i = 0 ; i < level ; i++) {
4254d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            indent += "    ";
4264d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
4274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Print the current node
428e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        Log.v(LOGTAG, indent + "current group is :" +  currentGroup.getGroupName()
4294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                + " rotation is " + currentGroup.mRotate);
4304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        Log.v(LOGTAG, indent + "matrix is :" +  currentGroup.getLocalMatrix().toString());
4314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Then print all the children
4324d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
4334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            printGroupTree(currentGroup.mChildGroupList.get(i), level + 1);
4344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
4354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui    }
4364d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
437ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private void setPathRenderer(VPathRenderer pathRenderer) {
438ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer = pathRenderer;
439abb7d134c02ac60091108c491dafb00877093170John Hoford    }
440abb7d134c02ac60091108c491dafb00877093170John Hoford
4415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
4425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
443ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        VPathRenderer mVPathRenderer;
4445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
445b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        ColorStateList mTint;
446b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        Mode mTintMode;
4475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
4495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
4505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
4514d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                // TODO: Make sure the constant state are handled correctly.
452ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
4535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
454b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette                mTint = copy.mTint;
455b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette                mTintMode = copy.mTintMode;
4565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
4575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
4615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
4625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
4665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
4675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
4715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
4725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
4765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
4775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
4795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
480ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private static class VPathRenderer {
4814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        /* Right now the internal data structure is organized as a tree.
4824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * Each node can be a group node, or a path.
4834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * A group node can have groups or paths as children, but a path node has
4844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * no children.
4854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * One example can be:
4864d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *                 Root Group
4874d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *                /    |     \
4884d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *           Group    Path    Group
4894d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *          /     \             |
4904d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *         Path   Path         Path
4914d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *
4924d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         */
4934d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final VGroup mRootGroup;
4944d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
4954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
4964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
4974d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private static final Matrix IDENTITY_MATRIX = new Matrix();
4984b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
4994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
5004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
501fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        private ColorFilter mColorFilter;
502abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
5034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5044d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mBaseWidth = 0;
5054d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mBaseHeight = 0;
5064d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mViewportWidth = 0;
5074d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mViewportHeight = 0;
5082af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        private int mRootAlpha = 0xFF;
5099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5104d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final Matrix mFinalPathMatrix = new Matrix();
511abb7d134c02ac60091108c491dafb00877093170John Hoford
512ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer() {
5134d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mRootGroup = new VGroup();
514abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5162af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        public void setRootAlpha(int alpha) {
5172af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            mRootAlpha = alpha;
5182af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        }
5192af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui
5202af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        public int getRootAlpha() {
5212af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            return mRootAlpha;
5222af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        }
5232af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui
524ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer(VPathRenderer copy) {
5254d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mRootGroup = copy.mRootGroup;
526abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
527abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
528abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
529abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
530abb7d134c02ac60091108c491dafb00877093170John Hoford        }
531abb7d134c02ac60091108c491dafb00877093170John Hoford
5329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
5334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // If one of the paths can apply theme, then return true;
5344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return recursiveCanApplyTheme(mRootGroup);
5354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
5364d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5374d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private boolean recursiveCanApplyTheme(VGroup currentGroup) {
5384d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // We can do a tree traverse here, if there is one path return true,
5394d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // then we return true for the whole tree.
5404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VPath> paths = currentGroup.mPathList;
5414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int j = paths.size() - 1; j >= 0; j--) {
5424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final VPath path = paths.get(j);
5434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (path.canApplyTheme()) {
5444d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    return true;
5459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
5469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
5476d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
5484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
5494d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5504d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int i = 0; i < childGroups.size(); i++) {
5514d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                VGroup childGroup = childGroups.get(i);
5524d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (childGroup.canApplyTheme()
5534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                        || recursiveCanApplyTheme(childGroup)) {
5544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    return true;
5554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                }
5564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
5579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
5589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
5599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
5614d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Apply theme to every path of the tree.
5624d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            recursiveApplyTheme(mRootGroup, t);
5634d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
5644d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5654d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
5664d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // We can do a tree traverse here, apply theme to all paths which
5674d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // can apply theme.
5684d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VPath> paths = currentGroup.mPathList;
5694d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int j = paths.size() - 1; j >= 0; j--) {
5704d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final VPath path = paths.get(j);
5714d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (path.canApplyTheme()) {
5724d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    path.applyTheme(t);
5739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
5749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
5754d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5764d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
5774d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5784d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int i = 0; i < childGroups.size(); i++) {
5794d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                VGroup childGroup = childGroups.get(i);
5804d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (childGroup.canApplyTheme()) {
5814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    childGroup.applyTheme(t);
5824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                }
5834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                recursiveApplyTheme(childGroup, t);
5844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
5854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
586abb7d134c02ac60091108c491dafb00877093170John Hoford        }
587abb7d134c02ac60091108c491dafb00877093170John Hoford
588fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        public void setColorFilter(ColorFilter colorFilter) {
589fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mColorFilter = colorFilter;
590fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
591fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mFillPaint != null) {
592fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                mFillPaint.setColorFilter(colorFilter);
593fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            }
594fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
595fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mStrokePaint != null) {
596fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                mStrokePaint.setColorFilter(colorFilter);
597fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            }
5986d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
599fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        }
600fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
6014d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
6022af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                float currentAlpha, Canvas canvas, int w, int h) {
6034d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Calculate current group's matrix by preConcat the parent's and
6044d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // and the current one on the top of the stack.
6054d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
6064d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Mi the local matrix at level i of the group tree.
6074d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            currentGroup.mStackedMatrix.set(currentMatrix);
6084d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
6094d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
6104d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
6112af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            float stackedAlpha = currentAlpha * currentGroup.mGroupAlpha;
6122af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            drawPath(currentGroup, stackedAlpha, canvas, w, h);
6134d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Draw the group tree in post order.
6144d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
6154d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                drawGroupTree(currentGroup.mChildGroupList.get(i),
6162af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        currentGroup.mStackedMatrix, stackedAlpha, canvas, w, h);
617abb7d134c02ac60091108c491dafb00877093170John Hoford            }
6184d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
619abb7d134c02ac60091108c491dafb00877093170John Hoford
6204d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        public void draw(Canvas canvas, int w, int h) {
6214d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Travese the tree in pre-order to draw.
6222af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h);
623abb7d134c02ac60091108c491dafb00877093170John Hoford        }
624abb7d134c02ac60091108c491dafb00877093170John Hoford
6252af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        private void drawPath(VGroup vGroup, float stackedAlpha, Canvas canvas, int w, int h) {
6269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
627abb7d134c02ac60091108c491dafb00877093170John Hoford
6284d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mFinalPathMatrix.set(vGroup.mStackedMatrix);
6294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mFinalPathMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
6304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mFinalPathMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
631abb7d134c02ac60091108c491dafb00877093170John Hoford
63263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            ArrayList<VPath> paths = vGroup.getPaths();
63363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            for (int i = 0; i < paths.size(); i++) {
63463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                VPath vPath = paths.get(i);
63563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                vPath.toPath(mPath);
63663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                final Path path = mPath;
637abb7d134c02ac60091108c491dafb00877093170John Hoford
63863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
63963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
64063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
6419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
64263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (mPathMeasure == null) {
64363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure = new PathMeasure();
64463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
64563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mPathMeasure.setPath(mPath, false);
64663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
64763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float len = mPathMeasure.getLength();
64863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    start = start * len;
64963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    end = end * len;
65063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    path.reset();
65163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (start > end) {
65263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(start, len, path, true);
65363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(0f, end, path, true);
65463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    } else {
65563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(start, end, path, true);
65663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
65763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    path.rLineTo(0, 0); // fix bug in measure
6584b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
6594b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
66063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRenderPath.reset();
6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6624d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                mRenderPath.addPath(path, mFinalPathMatrix);
6634b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
66463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mClip) {
66563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    canvas.clipPath(mRenderPath, Region.Op.REPLACE);
6662af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                } else {
6672af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                   if (vPath.mFillColor != 0) {
6682af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (mFillPaint == null) {
6692af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint = new Paint();
6702af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint.setColorFilter(mColorFilter);
6712af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint.setStyle(Paint.Style.FILL);
6722af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint.setAntiAlias(true);
6732af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
6742af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha));
6752af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        canvas.drawPath(mRenderPath, mFillPaint);
67663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
67763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
6782af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                    if (vPath.mStrokeColor != 0) {
6792af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (mStrokePaint == null) {
6802af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint = new Paint();
6812af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint.setColorFilter(mColorFilter);
6822af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint.setStyle(Paint.Style.STROKE);
6832af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint.setAntiAlias(true);
6842af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
6854b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
6862af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        final Paint strokePaint = mStrokePaint;
6872af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (vPath.mStrokeLineJoin != null) {
6882af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
6892af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
690abb7d134c02ac60091108c491dafb00877093170John Hoford
6912af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (vPath.mStrokeLineCap != null) {
6922af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            strokePaint.setStrokeCap(vPath.mStrokeLineCap);
6932af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
69463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
6952af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
69663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
6972af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha));
6982af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
6992af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        canvas.drawPath(mRenderPath, strokePaint);
7002af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                    }
70163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                }
702abb7d134c02ac60091108c491dafb00877093170John Hoford            }
703abb7d134c02ac60091108c491dafb00877093170John Hoford        }
704abb7d134c02ac60091108c491dafb00877093170John Hoford
705abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
706abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
7074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
708fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth);
709fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight);
710fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
711fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mViewportWidth <= 0) {
712fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
713fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<viewport> tag requires viewportWidth > 0");
714fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            } else if (mViewportHeight <= 0) {
715fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
716fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<viewport> tag requires viewportHeight > 0");
717abb7d134c02ac60091108c491dafb00877093170John Hoford            }
718fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
719abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
720abb7d134c02ac60091108c491dafb00877093170John Hoford        }
721abb7d134c02ac60091108c491dafb00877093170John Hoford
722abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
723abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
7244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
725fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth);
726fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight);
727fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
728fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mBaseWidth <= 0) {
729fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
730fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<size> tag requires width > 0");
731fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            } else if (mBaseHeight <= 0) {
732fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
733fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<size> tag requires height > 0");
734abb7d134c02ac60091108c491dafb00877093170John Hoford            }
735fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
736abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
737abb7d134c02ac60091108c491dafb00877093170John Hoford        }
7384b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
739abb7d134c02ac60091108c491dafb00877093170John Hoford    }
740abb7d134c02ac60091108c491dafb00877093170John Hoford
741e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    static class VGroup {
7424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
7434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
744abb7d134c02ac60091108c491dafb00877093170John Hoford
74563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mRotate = 0;
74663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mPivotX = 0;
74763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mPivotY = 0;
748452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mScaleX = 1;
749452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mScaleY = 1;
750452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mTranslateX = 0;
751452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mTranslateY = 0;
7522af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        private float mGroupAlpha = 1;
7534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
7544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // mLocalMatrix is parsed from the XML.
7554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final Matrix mLocalMatrix = new Matrix();
7564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // mStackedMatrix is only used when drawing, it combines all the
7574d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // parents' local matrices with the current one.
7584d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final Matrix mStackedMatrix = new Matrix();
75963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
76063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private int[] mThemeAttrs;
76163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
762e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        private String mGroupName = null;
763e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
764e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        /* Getter and Setter */
765e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getRotation() {
766e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mRotate;
767e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
768e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
769e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setRotation(float rotation) {
770e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (rotation != mRotate) {
771e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mRotate = rotation;
772e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
773e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
774e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
775e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
776e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getPivotX() {
777e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mPivotX;
778e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
779e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
780e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setPivotX(float pivotX) {
781e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (pivotX != mPivotX) {
782e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPivotX = pivotX;
783e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
784e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
785e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
786e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
787e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getPivotY() {
788e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mPivotY;
789e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
790e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
791e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setPivotY(float pivotY) {
792e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (pivotY != mPivotY) {
793e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPivotY = pivotY;
794e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
795e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
796e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
797e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
798e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getScaleX() {
799e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mScaleX;
800e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
8014d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
802e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setScaleX(float scaleX) {
803e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (scaleX != mScaleX) {
804e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mScaleX = scaleX;
805e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
806e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
807e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
808e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
809e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getScaleY() {
810e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mScaleY;
811e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
812e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
813e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setScaleY(float scaleY) {
814e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (scaleY != mScaleY) {
815e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mScaleY = scaleY;
816e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
817e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
818e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
819e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
820e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getTranslateX() {
821e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTranslateX;
822e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
823e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
824e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setTranslateX(float translateX) {
825e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (translateX != mTranslateX) {
826e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mTranslateX = translateX;
827e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
828e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
829e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
830e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
831e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getTranslateY() {
832e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTranslateY;
833e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
834e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
835e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setTranslateY(float translateY) {
836e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (translateY != mTranslateY) {
837e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mTranslateY = translateY;
838e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
839e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
840e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
841e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
842e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getAlpha() {
843e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mGroupAlpha;
844e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
845e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
846e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setAlpha(float groupAlpha) {
847e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (groupAlpha != mGroupAlpha) {
848e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mGroupAlpha = groupAlpha;
849e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
850e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
851e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
852e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public String getGroupName() {
853e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mGroupName;
8544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
8554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
8564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        public Matrix getLocalMatrix() {
8574d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return mLocalMatrix;
8584d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
8594d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
860abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
8614d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mPathList.add(path);
862abb7d134c02ac60091108c491dafb00877093170John Hoford         }
863abb7d134c02ac60091108c491dafb00877093170John Hoford
8644d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        public boolean canApplyTheme() {
8654d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return mThemeAttrs != null;
8664d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
8674d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
86863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public void applyTheme(Theme t) {
86963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (mThemeAttrs == null) {
87063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                return;
87163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
87263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
87363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final TypedArray a = t.resolveAttributes(
87463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mThemeAttrs, R.styleable.VectorDrawablePath);
87563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
87663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
87763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
87863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
879452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
880452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
881452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
882452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
8832af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
8844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            updateLocalMatrix();
8854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
886e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
8874d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
88863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
88963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        }
89063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
89163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
89263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup);
89363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final int[] themeAttrs = a.extractThemeAttrs();
89463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
89563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mThemeAttrs = themeAttrs;
89663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            // NOTE: The set of attributes loaded here MUST match the
89763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            // set of attributes loaded in applyTheme.
89863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
89963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) {
90063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
90163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
90263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
90363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) {
90463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
90563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
90663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
90763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) {
90863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
90963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
91063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
911452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleX] == 0) {
912452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
913452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
914452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
915452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleY] == 0) {
916452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
917452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
918452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
919452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateX] == 0) {
920452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
921452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
922452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
923452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateY] == 0) {
924452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
925452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
926452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
9274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
928e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
9294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
9304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
9314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
9322af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
9334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
9344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
9354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            updateLocalMatrix();
93663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
93763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        }
93863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
9394d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private void updateLocalMatrix() {
9404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // The order we apply is the same as the
9414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // RenderNode.cpp::applyViewPropertyTransforms().
9424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.reset();
9434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
9444d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postScale(mScaleX, mScaleY);
9454d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postRotate(mRotate, 0, 0);
9464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
9474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
9484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
949abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
950abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
951abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
952abb7d134c02ac60091108c491dafb00877093170John Hoford         */
95363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public ArrayList<VPath> getPaths() {
9544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return mPathList;
955abb7d134c02ac60091108c491dafb00877093170John Hoford        }
956abb7d134c02ac60091108c491dafb00877093170John Hoford
957abb7d134c02ac60091108c491dafb00877093170John Hoford    }
958abb7d134c02ac60091108c491dafb00877093170John Hoford
959e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    static class VPath {
9609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
9619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
962abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
963abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
964abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
9652af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        int mFillColor = Color.BLACK;
966abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
967abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
968abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
969abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
970abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
9719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
972abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
9734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
9744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
975abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
9769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
978e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        private String mPathName;
979abb7d134c02ac60091108c491dafb00877093170John Hoford
9809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
9819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
9829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
9839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
984abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
985abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
986abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
987abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
988abb7d134c02ac60091108c491dafb00877093170John Hoford            }
989abb7d134c02ac60091108c491dafb00877093170John Hoford        }
990abb7d134c02ac60091108c491dafb00877093170John Hoford
991e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public String getPathName() {
992e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mPathName;
993abb7d134c02ac60091108c491dafb00877093170John Hoford        }
994abb7d134c02ac60091108c491dafb00877093170John Hoford
9957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
9967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
9977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
9987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
9997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
10007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
10017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
10027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
10037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
10047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
10057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
10077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
10087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
10097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
10107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
10117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
10127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
10137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
10147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
10157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
10167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
10177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
10187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
10207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
1021e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        /* Setters and Getters */
1022e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int getStroke() {
1023e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mStrokeColor;
1024e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1025e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1026e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setStroke(int strokeColor) {
1027e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mStrokeColor = strokeColor;
1028e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1029e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1030e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getStrokeWidth() {
1031e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mStrokeWidth;
1032e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1033e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1034e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setStrokeWidth(float strokeWidth) {
1035e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mStrokeWidth = strokeWidth;
1036e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1037e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1038e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getStrokeOpacity() {
1039e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mStrokeOpacity;
1040e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1041e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1042e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setStrokeOpacity(float strokeOpacity) {
1043e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mStrokeOpacity = strokeOpacity;
1044e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1045e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1046e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int getFill() {
1047e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mFillColor;
1048e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1049e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1050e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setFill(int fillColor) {
1051e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mFillColor = fillColor;
1052e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1053e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1054e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getFillOpacity() {
1055e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mFillOpacity;
1056e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1057e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1058e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setFillOpacity(float fillOpacity) {
1059e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mFillOpacity = fillOpacity;
1060e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1061e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1062e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getTrimPathStart() {
1063e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTrimPathStart;
1064e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1065e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1066e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setTrimPathStart(float trimPathStart) {
1067e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mTrimPathStart = trimPathStart;
1068e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1069e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1070e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getTrimPathEnd() {
1071e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTrimPathEnd;
1072e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1073e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1074e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setTrimPathEnd(float trimPathEnd) {
1075e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mTrimPathEnd = trimPathEnd;
1076e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1077e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1078e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getTrimPathOffset() {
1079e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTrimPathOffset;
1080e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1081e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1082e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setTrimPathOffset(float trimPathOffset) {
1083e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mTrimPathOffset = trimPathOffset;
1084e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1085e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
10869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
10879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
10889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
10899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
10909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
10927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
10937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
10947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
10957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
10977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
1098e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
10997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
11027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
11037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
1104abb7d134c02ac60091108c491dafb00877093170John Hoford
11059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
11067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
11079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
11107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1111abb7d134c02ac60091108c491dafb00877093170John Hoford            }
11129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
11157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
11167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
11177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
11217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
11227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1123abb7d134c02ac60091108c491dafb00877093170John Hoford            }
11249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
11277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
11287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
11297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
11329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1133abb7d134c02ac60091108c491dafb00877093170John Hoford            }
11349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
11369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
11379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
11387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
11399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
11427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
11437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
11467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
11477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
11517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
11527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
11537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
11577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
11587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
11597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
11629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1163abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1164abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1165abb7d134c02ac60091108c491dafb00877093170John Hoford
11669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
11679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
11689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
11699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
11719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
11729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
11739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
11760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath);
11779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
11799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
1181e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
11829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
11857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
11869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
11897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
11907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
11927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
11937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
11947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
11957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
11967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
11977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
11987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
11997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
12007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
12017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
12027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
12037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
12047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
12057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
12067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
12079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
120963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
12109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
12119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
12139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
12142af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                mFillColor = applyAlpha(mFillColor, mFillOpacity);
12159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
12169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
12182af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity);
12199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
12209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
12219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1222abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
1224abb7d134c02ac60091108c491dafb00877093170John Hoford
1225abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
1226abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
1229abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1230abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1231abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1232abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
1233abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1234abb7d134c02ac60091108c491dafb00877093170John Hoford
1235abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
1236abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
1237abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1238abb7d134c02ac60091108c491dafb00877093170John Hoford
1239abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1240abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
1241abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
1242abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
1243abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1244abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
1245abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
1246abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1247abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
1248abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
1249abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
1250abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1251abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
1252abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
1253abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
1254abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
1255abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
1256abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
1257abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
1258abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1259abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
1260abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1261abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
1262abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
1263abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
1264abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1265abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
1266abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
1267abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
1268abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
1269abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1270abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1271abb7d134c02ac60091108c491dafb00877093170John Hoford
1272abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1273abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
1274abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
1275abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
1276abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
1277abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1278abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
1279abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
1280abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
1281abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
1282abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
1283abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1284abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
1285abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
1286abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1287abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
1288abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1289abb7d134c02ac60091108c491dafb00877093170John Hoford
1290abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
1291abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
1292abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
1293abb7d134c02ac60091108c491dafb00877093170John Hoford
1294abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
1295abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
1296abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
1297abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
1298abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
1299abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
1300abb7d134c02ac60091108c491dafb00877093170John Hoford
1301abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
1302abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1303abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1304abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
1305abb7d134c02ac60091108c491dafb00877093170John Hoford
1306abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
1307abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1308abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
1309abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1310abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1311abb7d134c02ac60091108c491dafb00877093170John Hoford
1312abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
13135c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
13145c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
13159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1316abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
13175c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
13185c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
1319abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1320abb7d134c02ac60091108c491dafb00877093170John Hoford
1321abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
13225c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
13235c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
1324abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1325abb7d134c02ac60091108c491dafb00877093170John Hoford
1326abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
13275c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
132833ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
1329abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
133033ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
133133ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
1332abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1333abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1334abb7d134c02ac60091108c491dafb00877093170John Hoford
133533ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
133633ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
1337abb7d134c02ac60091108c491dafb00877093170John Hoford
1338abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
1339abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
1340abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
1341abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
1342abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
134333ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
134433ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
1345abb7d134c02ac60091108c491dafb00877093170John Hoford
1346abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
1347abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
1348abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
1349abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
1350abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
1351abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
1352abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
1353abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
1354abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
1355abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
1356abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
1357abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
1358abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1359abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
1360abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
1361abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
1362abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
1363abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
1364abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1365abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
1366abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
1367abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1368abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1369abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1370abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1371abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1372abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1373abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1374abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1375abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1376abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1377abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1378abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1379abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1380abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1381abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1382abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1383abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1384abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1385abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1386abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1387abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1388abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1389abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1390abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1391abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1392abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1393abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1394abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1395abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1396abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1397abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1398abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1399abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1400abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1401abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1402abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1403abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1404abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1405abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1406abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1407abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1408abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1409abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1410abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1411abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1412abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1413abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1414abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1415abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1416abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1417abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1418abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1419abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1420abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1421abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1422abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
142333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
142433ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1425abb7d134c02ac60091108c491dafb00877093170John Hoford
1426abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1427abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1428abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1429abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1430abb7d134c02ac60091108c491dafb00877093170John Hoford
1431abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1432abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
143333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
143433ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1435abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1436abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1437abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1438abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1439abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1440abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
144133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
144233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
144333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
144433ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
144533ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
144633ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
144733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
144833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1449abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1450abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1451abb7d134c02ac60091108c491dafb00877093170John Hoford
1452abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1453abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1454abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1455abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1456abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1457abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
145833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
145933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
146033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
146133ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
146233ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
146333ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
146433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
146533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
146633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1467abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1468abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
146933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
147033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1471abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1472abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1473abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
147433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
147533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1476abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1477abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1478abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1479abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1480abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1481abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1482abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
148333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
148433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1485abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1486abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
148733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
148833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
148933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
149033ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
149133ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
149233ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
149333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
149433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1495abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1496175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
1497175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
1498abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1499abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1500abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1501abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
150233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
150333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
150433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
150533ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
150633ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
150733ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
150833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
150933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1510abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
151133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
151233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
1513abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
151433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
1515abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1516abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1517abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1518abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1519abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1520abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1521abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1522abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1523abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1524abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1525abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1526abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1527abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1528abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1529abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1530abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1531abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1532abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1533abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1534abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1535abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1536abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1537abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1538abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1539abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1540abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1541abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1542abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1543abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1544abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1545abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
1546abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1547abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1548abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1549abb7d134c02ac60091108c491dafb00877093170John Hoford                }
155033ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
1551abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1552abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
1553abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
1554abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
1555abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
1556abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1557abb7d134c02ac60091108c491dafb00877093170John Hoford
1558abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
1559abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
1560abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
1561abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
1562abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
1563abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
1564abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
1565abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
1566abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
1567abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
1568abb7d134c02ac60091108c491dafb00877093170John Hoford
1569abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
1570abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
1571abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
1572abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
1573abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
1574abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
1575abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
1576abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
1577abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
1578abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
1579abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
1580abb7d134c02ac60091108c491dafb00877093170John Hoford
1581abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
1582abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
1583abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
1584abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
1585abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
1586abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
1587abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
1588abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
1589abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
1590abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
1591abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1592abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
1593abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
1594abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
1595abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
1596abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
1597abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
1598abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
1599abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1600abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
1601abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
1602abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
1603abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
1604abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
1605abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
1606abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
1607abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
1608abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1609abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
1610abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
1611abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1612abb7d134c02ac60091108c491dafb00877093170John Hoford
1613abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
1614abb7d134c02ac60091108c491dafb00877093170John Hoford
1615abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
1616abb7d134c02ac60091108c491dafb00877093170John Hoford
1617abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
1618abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
1619abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
1620abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
1621abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1622abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
1623abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1624abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1625abb7d134c02ac60091108c491dafb00877093170John Hoford
1626abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
1627abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
1628abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
1629abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
1630abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
1631abb7d134c02ac60091108c491dafb00877093170John Hoford
1632abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
1633abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1634abb7d134c02ac60091108c491dafb00877093170John Hoford
1635abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1636abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
1637abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1638abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
1639abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
1640abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
1641abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
1642abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
1643abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
1644abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
1645abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
1646abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
1647abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
1648abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1649abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
1650abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
1651abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
1652abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
1653abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
1654abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
1655abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
1656abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
1657abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
1658abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
1659abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
1660abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
1661abb7d134c02ac60091108c491dafb00877093170John Hoford
1662abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
1663abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
1664abb7d134c02ac60091108c491dafb00877093170John Hoford
1665abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
1666abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
1667abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
1668abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
1669abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
1670abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
1671abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
1672abb7d134c02ac60091108c491dafb00877093170John Hoford
1673abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
1674abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
1675abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
1676abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
1677abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
1678abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
1679abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
1680abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
1681abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
1682abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
1683abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
1684abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
1685abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
1686abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
1687abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
1688abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
1689abb7d134c02ac60091108c491dafb00877093170John Hoford
1690abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
1691abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
1692abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
1693abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
1694abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
1695abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
1696abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
1697abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
1698abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
1699abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
1700abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
1701abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1702abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1703abb7d134c02ac60091108c491dafb00877093170John Hoford
1704abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1705abb7d134c02ac60091108c491dafb00877093170John Hoford}
1706