VectorDrawable.java revision b3c56086d802ae28888dd97ba1f49bd6cee0b673
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) {
150abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
1519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
155b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
156b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
157b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
158abb7d134c02ac60091108c491dafb00877093170John Hoford    }
159abb7d134c02ac60091108c491dafb00877093170John Hoford
160e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    Object getTargetByName(String name) {
161e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return mVGTargetsMap.get(name);
162e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
163e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
164abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
165abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
166abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
167abb7d134c02ac60091108c491dafb00877093170John Hoford    }
168abb7d134c02ac60091108c491dafb00877093170John Hoford
1694554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette    @Override
170abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
1714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
1724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
1734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
174ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
1754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
176abb7d134c02ac60091108c491dafb00877093170John Hoford    }
177abb7d134c02ac60091108c491dafb00877093170John Hoford
178abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
179e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    public int getAlpha() {
180e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        return mVectorState.mVPathRenderer.getRootAlpha();
181e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    }
182e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
183e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    @Override
184abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
1852af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
1862af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            mVectorState.mVPathRenderer.setRootAlpha(alpha);
187abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
188abb7d134c02ac60091108c491dafb00877093170John Hoford        }
189abb7d134c02ac60091108c491dafb00877093170John Hoford    }
190abb7d134c02ac60091108c491dafb00877093170John Hoford
191abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
192abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
193b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final VectorDrawableState state = mVectorState;
194b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (colorFilter != null) {
195b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            // Color filter overrides tint.
196b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = null;
197b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        } else if (state.mTint != null && state.mTintMode != null) {
198b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            // Restore the tint filter, if we need one.
199b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT);
200b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
201b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            colorFilter = mTintFilter;
202b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        }
203b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
204b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        state.mVPathRenderer.setColorFilter(colorFilter);
205fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        invalidateSelf();
206abb7d134c02ac60091108c491dafb00877093170John Hoford    }
207abb7d134c02ac60091108c491dafb00877093170John Hoford
208abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
209b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    public void setTint(ColorStateList tint, Mode tintMode) {
210b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final VectorDrawableState state = mVectorState;
211b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (state.mTint != tint || state.mTintMode != tintMode) {
212b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            state.mTint = tint;
213b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            state.mTintMode = tintMode;
214b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
215b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
216b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
217b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            invalidateSelf();
218b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        }
219b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    }
220b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
221b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    @Override
222b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    protected boolean onStateChange(int[] stateSet) {
223b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        final VectorDrawableState state = mVectorState;
224b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        if (state.mTint != null && state.mTintMode != null) {
225b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
226b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
227b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette            return true;
228b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        }
229b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        return false;
230b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    }
231b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
232b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    @Override
233abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
234abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
235abb7d134c02ac60091108c491dafb00877093170John Hoford    }
236abb7d134c02ac60091108c491dafb00877093170John Hoford
237abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
238d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * Sets padding for this shape, defined by a Rect object. Define the padding
239d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * in the Rect object as: left, top, right, bottom.
240abb7d134c02ac60091108c491dafb00877093170John Hoford     */
241abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
242abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
243abb7d134c02ac60091108c491dafb00877093170John Hoford    }
244abb7d134c02ac60091108c491dafb00877093170John Hoford
245abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
246abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
247abb7d134c02ac60091108c491dafb00877093170John Hoford     *
248abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
249abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
250abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
251abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
252abb7d134c02ac60091108c491dafb00877093170John Hoford     */
253abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
254abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
255abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
256abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
257abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
258abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
259abb7d134c02ac60091108c491dafb00877093170John Hoford            }
260abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
261abb7d134c02ac60091108c491dafb00877093170John Hoford        }
262abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
263abb7d134c02ac60091108c491dafb00877093170John Hoford    }
264abb7d134c02ac60091108c491dafb00877093170John Hoford
265abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
266abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
267ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseWidth;
268abb7d134c02ac60091108c491dafb00877093170John Hoford    }
269abb7d134c02ac60091108c491dafb00877093170John Hoford
270abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
271abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
272ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseHeight;
273abb7d134c02ac60091108c491dafb00877093170John Hoford    }
274abb7d134c02ac60091108c491dafb00877093170John Hoford
275abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
276abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
277abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
278abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
279abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
280abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
281abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
282abb7d134c02ac60091108c491dafb00877093170John Hoford        }
283abb7d134c02ac60091108c491dafb00877093170John Hoford    }
284abb7d134c02ac60091108c491dafb00877093170John Hoford
285abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
286abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
287abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
288ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
289ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        setPathRenderer(p);
290abb7d134c02ac60091108c491dafb00877093170John Hoford    }
291abb7d134c02ac60091108c491dafb00877093170John Hoford
2929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
2959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
2999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
3009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
302ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer path = state.mVPathRenderer;
3039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
3049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
3059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
3079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3084b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    /** @hide */
3094b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    public static VectorDrawable create(Resources resources, int rid) {
3104b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        try {
3114b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParser xpp = resources.getXml(rid);
3124b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final AttributeSet attrs = Xml.asAttributeSet(xpp);
3134b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
3144b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            factory.setNamespaceAware(true);
3154b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
3164b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final VectorDrawable drawable = new VectorDrawable();
3174b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.inflate(resources, xpp, attrs);
3184b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
3194b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            return drawable;
3204b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (XmlPullParserException e) {
3214b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
3224b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (IOException e) {
3234b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
3244b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        }
3254b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        return null;
3264b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    }
3274b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
3282af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui    private static int applyAlpha(int color, float alpha) {
3292af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        int alphaBytes = Color.alpha(color);
3302af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        color &= 0x00FFFFFF;
3312af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        color |= ((int) (alphaBytes * alpha)) << 24;
3322af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        return color;
3332af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui    }
3342af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui
335ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
3369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer pathRenderer = new VPathRenderer();
3389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
339abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
340abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
3416d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        boolean noGroupTag = true;
342abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
3439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3444d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Use a stack to help to build the group tree.
3454d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // The top of the stack is always the current group.
3464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        final Stack<VGroup> groupStack = new Stack<VGroup>();
3474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        groupStack.push(pathRenderer.mRootGroup);
348abb7d134c02ac60091108c491dafb00877093170John Hoford
349abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
350abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
351abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
3529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
3534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final VGroup currentGroup = groupStack.peek();
3544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
355abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
3569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
3579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
3589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
359e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    if (path.getPathName() != null) {
360e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                        mVGTargetsMap.put(path.getPathName(), path);
361e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    }
362abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
363abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
364ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseSize(res, attrs);
365abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
366abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
367ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseViewport(res, attrs);
368abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
3696d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                } else if (SHAPE_GROUP.equals(tagName)) {
3704d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    VGroup newChildGroup = new VGroup();
3714d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    newChildGroup.inflate(res, attrs, theme);
3724d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    currentGroup.mChildGroupList.add(newChildGroup);
3734d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    groupStack.push(newChildGroup);
374e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    if (newChildGroup.getGroupName() != null) {
375e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                        mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
376e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                    }
3776d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui                    noGroupTag = false;
378abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3794d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            } else if (eventType == XmlPullParser.END_TAG) {
3804d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final String tagName = parser.getName();
3814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (SHAPE_GROUP.equals(tagName)) {
3824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    groupStack.pop();
3834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                }
384abb7d134c02ac60091108c491dafb00877093170John Hoford            }
385abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
386abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3884d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Print the tree out for debug.
3894d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        if (DBG_VECTOR_DRAWABLE) {
3904d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            printGroupTree(pathRenderer.mRootGroup, 0);
3916d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui        }
3926d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
39346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        if (noSizeTag || noViewportTag || noPathTag) {
3949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
3959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
396abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
3979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
398abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
400d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noViewportTag) {
401d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
402abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
403abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
405abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
407d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noPathTag) {
408d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
409abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
410abb7d134c02ac60091108c491dafb00877093170John Hoford                }
4119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
412abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
415abb7d134c02ac60091108c491dafb00877093170John Hoford        }
4169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
417ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return pathRenderer;
418abb7d134c02ac60091108c491dafb00877093170John Hoford    }
419abb7d134c02ac60091108c491dafb00877093170John Hoford
4204d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui    private void printGroupTree(VGroup currentGroup, int level) {
4214d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        String indent = "";
4224d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        for (int i = 0 ; i < level ; i++) {
4234d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            indent += "    ";
4244d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
4254d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Print the current node
426e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        Log.v(LOGTAG, indent + "current group is :" +  currentGroup.getGroupName()
4274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                + " rotation is " + currentGroup.mRotate);
4284d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        Log.v(LOGTAG, indent + "matrix is :" +  currentGroup.getLocalMatrix().toString());
4294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // Then print all the children
4304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
4314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            printGroupTree(currentGroup.mChildGroupList.get(i), level + 1);
4324d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
4334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui    }
4344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
435ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private void setPathRenderer(VPathRenderer pathRenderer) {
436ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer = pathRenderer;
437abb7d134c02ac60091108c491dafb00877093170John Hoford    }
438abb7d134c02ac60091108c491dafb00877093170John Hoford
4395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
4405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
441ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        VPathRenderer mVPathRenderer;
4425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
443b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        ColorStateList mTint;
444b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette        Mode mTintMode;
4455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
4475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
4485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
4494d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                // TODO: Make sure the constant state are handled correctly.
450ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
4515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
452b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette                mTint = copy.mTint;
453b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette                mTintMode = copy.mTintMode;
4545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
4555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
4595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
4605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
4645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
4655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
4695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
4705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
4725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
4735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
4745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
4755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
4765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
4775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
478ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private static class VPathRenderer {
4794d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        /* Right now the internal data structure is organized as a tree.
4804d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * Each node can be a group node, or a path.
4814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * A group node can have groups or paths as children, but a path node has
4824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * no children.
4834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         * One example can be:
4844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *                 Root Group
4854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *                /    |     \
4864d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *           Group    Path    Group
4874d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *          /     \             |
4884d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *         Path   Path         Path
4894d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         *
4904d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui         */
4914d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final VGroup mRootGroup;
4924d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
4934b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
4944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
4954d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private static final Matrix IDENTITY_MATRIX = new Matrix();
4964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
4974b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
4984b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
499fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        private ColorFilter mColorFilter;
500abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
5014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5024d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mBaseWidth = 0;
5034d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mBaseHeight = 0;
5044d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mViewportWidth = 0;
5054d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private float mViewportHeight = 0;
5062af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        private int mRootAlpha = 0xFF;
5079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5084d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final Matrix mFinalPathMatrix = new Matrix();
509abb7d134c02ac60091108c491dafb00877093170John Hoford
510ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer() {
5114d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mRootGroup = new VGroup();
512abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5142af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        public void setRootAlpha(int alpha) {
5152af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            mRootAlpha = alpha;
5162af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        }
5172af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui
5182af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        public int getRootAlpha() {
5192af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            return mRootAlpha;
5202af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        }
5212af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui
522ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer(VPathRenderer copy) {
5234d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mRootGroup = copy.mRootGroup;
524abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
525abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
526abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
527abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
528abb7d134c02ac60091108c491dafb00877093170John Hoford        }
529abb7d134c02ac60091108c491dafb00877093170John Hoford
5309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
5314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // If one of the paths can apply theme, then return true;
5324d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return recursiveCanApplyTheme(mRootGroup);
5334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
5344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private boolean recursiveCanApplyTheme(VGroup currentGroup) {
5364d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // We can do a tree traverse here, if there is one path return true,
5374d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // then we return true for the whole tree.
5384d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VPath> paths = currentGroup.mPathList;
5394d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int j = paths.size() - 1; j >= 0; j--) {
5404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final VPath path = paths.get(j);
5414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (path.canApplyTheme()) {
5424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    return true;
5439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
5449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
5456d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
5464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
5474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int i = 0; i < childGroups.size(); i++) {
5494d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                VGroup childGroup = childGroups.get(i);
5504d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (childGroup.canApplyTheme()
5514d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                        || recursiveCanApplyTheme(childGroup)) {
5524d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    return true;
5534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                }
5544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
5559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
5569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
5579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
5594d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Apply theme to every path of the tree.
5604d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            recursiveApplyTheme(mRootGroup, t);
5614d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
5624d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5634d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
5644d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // We can do a tree traverse here, apply theme to all paths which
5654d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // can apply theme.
5664d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VPath> paths = currentGroup.mPathList;
5674d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int j = paths.size() - 1; j >= 0; j--) {
5684d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                final VPath path = paths.get(j);
5694d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (path.canApplyTheme()) {
5704d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    path.applyTheme(t);
5719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
5729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
5734d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5744d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
5754d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
5764d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int i = 0; i < childGroups.size(); i++) {
5774d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                VGroup childGroup = childGroups.get(i);
5784d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                if (childGroup.canApplyTheme()) {
5794d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                    childGroup.applyTheme(t);
5804d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                }
5814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                recursiveApplyTheme(childGroup, t);
5824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
5834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
584abb7d134c02ac60091108c491dafb00877093170John Hoford        }
585abb7d134c02ac60091108c491dafb00877093170John Hoford
586fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        public void setColorFilter(ColorFilter colorFilter) {
587fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mColorFilter = colorFilter;
588fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
589fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mFillPaint != null) {
590fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                mFillPaint.setColorFilter(colorFilter);
591fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            }
592fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
593fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mStrokePaint != null) {
594fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                mStrokePaint.setColorFilter(colorFilter);
595fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            }
5966d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui
597fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette        }
598fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
5994d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
6002af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                float currentAlpha, Canvas canvas, int w, int h) {
6014d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Calculate current group's matrix by preConcat the parent's and
6024d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // and the current one on the top of the stack.
6034d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
6044d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Mi the local matrix at level i of the group tree.
6054d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            currentGroup.mStackedMatrix.set(currentMatrix);
6064d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
6074d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
6084d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
6092af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            float stackedAlpha = currentAlpha * currentGroup.mGroupAlpha;
6102af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            drawPath(currentGroup, stackedAlpha, canvas, w, h);
6114d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Draw the group tree in post order.
6124d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
6134d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                drawGroupTree(currentGroup.mChildGroupList.get(i),
6142af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        currentGroup.mStackedMatrix, stackedAlpha, canvas, w, h);
615abb7d134c02ac60091108c491dafb00877093170John Hoford            }
6164d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
617abb7d134c02ac60091108c491dafb00877093170John Hoford
6184d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        public void draw(Canvas canvas, int w, int h) {
6194d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // Travese the tree in pre-order to draw.
6202af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h);
621abb7d134c02ac60091108c491dafb00877093170John Hoford        }
622abb7d134c02ac60091108c491dafb00877093170John Hoford
6232af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        private void drawPath(VGroup vGroup, float stackedAlpha, Canvas canvas, int w, int h) {
6249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
625abb7d134c02ac60091108c491dafb00877093170John Hoford
6264d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mFinalPathMatrix.set(vGroup.mStackedMatrix);
6274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mFinalPathMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
6284d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mFinalPathMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
629abb7d134c02ac60091108c491dafb00877093170John Hoford
63063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            ArrayList<VPath> paths = vGroup.getPaths();
63163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            for (int i = 0; i < paths.size(); i++) {
63263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                VPath vPath = paths.get(i);
63363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                vPath.toPath(mPath);
63463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                final Path path = mPath;
635abb7d134c02ac60091108c491dafb00877093170John Hoford
63663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
63763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
63863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
6399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
64063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (mPathMeasure == null) {
64163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure = new PathMeasure();
64263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
64363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mPathMeasure.setPath(mPath, false);
64463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
64563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    float len = mPathMeasure.getLength();
64663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    start = start * len;
64763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    end = end * len;
64863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    path.reset();
64963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    if (start > end) {
65063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(start, len, path, true);
65163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(0f, end, path, true);
65263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    } else {
65363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                        mPathMeasure.getSegment(start, end, path, true);
65463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
65563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    path.rLineTo(0, 0); // fix bug in measure
6564b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
6574b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
65863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRenderPath.reset();
6599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6604d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui                mRenderPath.addPath(path, mFinalPathMatrix);
6614b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
66263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                if (vPath.mClip) {
66363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    canvas.clipPath(mRenderPath, Region.Op.REPLACE);
6642af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                } else {
6652af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                   if (vPath.mFillColor != 0) {
6662af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (mFillPaint == null) {
6672af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint = new Paint();
6682af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint.setColorFilter(mColorFilter);
6692af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint.setStyle(Paint.Style.FILL);
6702af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mFillPaint.setAntiAlias(true);
6712af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
6722af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha));
6732af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        canvas.drawPath(mRenderPath, mFillPaint);
67463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    }
67563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
6762af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                    if (vPath.mStrokeColor != 0) {
6772af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (mStrokePaint == null) {
6782af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint = new Paint();
6792af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint.setColorFilter(mColorFilter);
6802af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint.setStyle(Paint.Style.STROKE);
6812af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            mStrokePaint.setAntiAlias(true);
6822af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
6834b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
6842af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        final Paint strokePaint = mStrokePaint;
6852af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (vPath.mStrokeLineJoin != null) {
6862af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
6872af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
688abb7d134c02ac60091108c491dafb00877093170John Hoford
6892af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        if (vPath.mStrokeLineCap != null) {
6902af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                            strokePaint.setStrokeCap(vPath.mStrokeLineCap);
6912af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        }
69263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
6932af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
69463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
6952af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha));
6962af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
6972af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                        canvas.drawPath(mRenderPath, strokePaint);
6982af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                    }
69963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                }
700abb7d134c02ac60091108c491dafb00877093170John Hoford            }
701abb7d134c02ac60091108c491dafb00877093170John Hoford        }
702abb7d134c02ac60091108c491dafb00877093170John Hoford
703abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
704abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
7054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
706fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth);
707fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight);
708fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
709fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mViewportWidth <= 0) {
710fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
711fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<viewport> tag requires viewportWidth > 0");
712fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            } else if (mViewportHeight <= 0) {
713fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
714fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<viewport> tag requires viewportHeight > 0");
715abb7d134c02ac60091108c491dafb00877093170John Hoford            }
716fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
717abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
718abb7d134c02ac60091108c491dafb00877093170John Hoford        }
719abb7d134c02ac60091108c491dafb00877093170John Hoford
720abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
721abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
7224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
723fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth);
724fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight);
725fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
726fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            if (mBaseWidth <= 0) {
727fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
728fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<size> tag requires width > 0");
729fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette            } else if (mBaseHeight <= 0) {
730fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                throw new XmlPullParserException(a.getPositionDescription() +
731fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette                        "<size> tag requires height > 0");
732abb7d134c02ac60091108c491dafb00877093170John Hoford            }
733fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette
734abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
735abb7d134c02ac60091108c491dafb00877093170John Hoford        }
7364b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
737abb7d134c02ac60091108c491dafb00877093170John Hoford    }
738abb7d134c02ac60091108c491dafb00877093170John Hoford
739e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    static class VGroup {
7404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
7414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
742abb7d134c02ac60091108c491dafb00877093170John Hoford
74363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mRotate = 0;
74463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mPivotX = 0;
74563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private float mPivotY = 0;
746452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mScaleX = 1;
747452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mScaleY = 1;
748452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mTranslateX = 0;
749452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui        private float mTranslateY = 0;
7502af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        private float mGroupAlpha = 1;
7514d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
7524d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // mLocalMatrix is parsed from the XML.
7534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final Matrix mLocalMatrix = new Matrix();
7544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // mStackedMatrix is only used when drawing, it combines all the
7554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        // parents' local matrices with the current one.
7564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private final Matrix mStackedMatrix = new Matrix();
75763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
75863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        private int[] mThemeAttrs;
75963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
760e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        private String mGroupName = null;
761e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
762e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        /* Getter and Setter */
763e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getRotation() {
764e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mRotate;
765e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
766e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
767e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setRotation(float rotation) {
768e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (rotation != mRotate) {
769e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mRotate = rotation;
770e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
771e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
772e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
773e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
774e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getPivotX() {
775e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mPivotX;
776e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
777e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
778e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setPivotX(float pivotX) {
779e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (pivotX != mPivotX) {
780e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPivotX = pivotX;
781e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
782e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
783e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
784e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
785e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getPivotY() {
786e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mPivotY;
787e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
788e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
789e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setPivotY(float pivotY) {
790e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (pivotY != mPivotY) {
791e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPivotY = pivotY;
792e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
793e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
794e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
795e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
796e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getScaleX() {
797e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mScaleX;
798e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
7994d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
800e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setScaleX(float scaleX) {
801e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (scaleX != mScaleX) {
802e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mScaleX = scaleX;
803e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
804e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
805e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
806e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
807e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getScaleY() {
808e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mScaleY;
809e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
810e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
811e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setScaleY(float scaleY) {
812e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (scaleY != mScaleY) {
813e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mScaleY = scaleY;
814e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
815e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
816e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
817e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
818e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getTranslateX() {
819e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTranslateX;
820e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
821e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
822e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setTranslateX(float translateX) {
823e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (translateX != mTranslateX) {
824e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mTranslateX = translateX;
825e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
826e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
827e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
828e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
829e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getTranslateY() {
830e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTranslateY;
831e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
832e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
833e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setTranslateY(float translateY) {
834e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (translateY != mTranslateY) {
835e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mTranslateY = translateY;
836e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                updateLocalMatrix();
837e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
838e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
839e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
840e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public float getAlpha() {
841e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mGroupAlpha;
842e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
843e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
844e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public void setAlpha(float groupAlpha) {
845e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            if (groupAlpha != mGroupAlpha) {
846e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mGroupAlpha = groupAlpha;
847e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            }
848e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
849e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
850e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public String getGroupName() {
851e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mGroupName;
8524d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
8534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
8544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        public Matrix getLocalMatrix() {
8554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return mLocalMatrix;
8564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
8574d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
858abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
8594d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mPathList.add(path);
860abb7d134c02ac60091108c491dafb00877093170John Hoford         }
861abb7d134c02ac60091108c491dafb00877093170John Hoford
8624d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        public boolean canApplyTheme() {
8634d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return mThemeAttrs != null;
8644d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
8654d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
86663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public void applyTheme(Theme t) {
86763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (mThemeAttrs == null) {
86863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                return;
86963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
87063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
87163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final TypedArray a = t.resolveAttributes(
87263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                    mThemeAttrs, R.styleable.VectorDrawablePath);
87363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
87463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
87563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
87663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
877452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
878452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
879452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
880452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
8812af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui            mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
8824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            updateLocalMatrix();
8834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
884e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
8854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
88663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
88763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        }
88863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
88963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
89063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup);
89163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            final int[] themeAttrs = a.extractThemeAttrs();
89263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
89363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            mThemeAttrs = themeAttrs;
89463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            // NOTE: The set of attributes loaded here MUST match the
89563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            // set of attributes loaded in applyTheme.
89663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
89763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) {
89863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
89963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
90063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
90163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) {
90263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
90363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
90463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
90563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) {
90663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui                mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
90763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            }
90863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
909452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleX] == 0) {
910452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
911452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
912452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
913452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleY] == 0) {
914452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
915452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
916452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
917452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateX] == 0) {
918452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
919452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
920452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
921452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateY] == 0) {
922452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui                mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
923452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui            }
924452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui
9254d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
926e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
9274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
9284d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
9294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
9302af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
9314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            }
9324d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
9334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            updateLocalMatrix();
93463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
93563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        }
93663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui
9374d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        private void updateLocalMatrix() {
9384d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // The order we apply is the same as the
9394d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            // RenderNode.cpp::applyViewPropertyTransforms().
9404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.reset();
9414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
9424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postScale(mScaleX, mScaleY);
9434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postRotate(mRotate, 0, 0);
9444d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
9454d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui        }
9464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui
947abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
948abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
949abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
950abb7d134c02ac60091108c491dafb00877093170John Hoford         */
95163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui        public ArrayList<VPath> getPaths() {
9524d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui            return mPathList;
953abb7d134c02ac60091108c491dafb00877093170John Hoford        }
954abb7d134c02ac60091108c491dafb00877093170John Hoford
955abb7d134c02ac60091108c491dafb00877093170John Hoford    }
956abb7d134c02ac60091108c491dafb00877093170John Hoford
957e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui    static class VPath {
9589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
9599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
960abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
961abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
962abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
9632af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui        int mFillColor = Color.BLACK;
964abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
965abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
966abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
967abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
968abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
9699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
970abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
9714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
9724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
973abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
9749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
9759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
976e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        private String mPathName;
977abb7d134c02ac60091108c491dafb00877093170John Hoford
9789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
9799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
9809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
9819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
982abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
983abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
984abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
985abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
986abb7d134c02ac60091108c491dafb00877093170John Hoford            }
987abb7d134c02ac60091108c491dafb00877093170John Hoford        }
988abb7d134c02ac60091108c491dafb00877093170John Hoford
989e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        public String getPathName() {
990e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mPathName;
991abb7d134c02ac60091108c491dafb00877093170John Hoford        }
992abb7d134c02ac60091108c491dafb00877093170John Hoford
9937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
9947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
9957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
9967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
9977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
9987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
9997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
10007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
10017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
10027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
10037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
10057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
10067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
10077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
10087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
10097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
10107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
10117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
10127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
10137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
10147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
10157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
10167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
10187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
1019e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        /* Setters and Getters */
1020e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int getStroke() {
1021e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mStrokeColor;
1022e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1023e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1024e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setStroke(int strokeColor) {
1025e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mStrokeColor = strokeColor;
1026e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1027e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1028e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getStrokeWidth() {
1029e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mStrokeWidth;
1030e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1031e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1032e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setStrokeWidth(float strokeWidth) {
1033e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mStrokeWidth = strokeWidth;
1034e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1035e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1036e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getStrokeOpacity() {
1037e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mStrokeOpacity;
1038e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1039e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1040e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setStrokeOpacity(float strokeOpacity) {
1041e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mStrokeOpacity = strokeOpacity;
1042e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1043e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1044e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        int getFill() {
1045e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mFillColor;
1046e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1047e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1048e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setFill(int fillColor) {
1049e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mFillColor = fillColor;
1050e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1051e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1052e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getFillOpacity() {
1053e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mFillOpacity;
1054e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1055e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1056e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setFillOpacity(float fillOpacity) {
1057e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mFillOpacity = fillOpacity;
1058e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1059e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1060e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getTrimPathStart() {
1061e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTrimPathStart;
1062e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1063e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1064e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setTrimPathStart(float trimPathStart) {
1065e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mTrimPathStart = trimPathStart;
1066e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1067e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1068e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getTrimPathEnd() {
1069e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTrimPathEnd;
1070e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1071e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1072e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setTrimPathEnd(float trimPathEnd) {
1073e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mTrimPathEnd = trimPathEnd;
1074e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1075e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1076e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        float getTrimPathOffset() {
1077e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            return mTrimPathOffset;
1078e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1079e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
1080e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        void setTrimPathOffset(float trimPathOffset) {
1081e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui            mTrimPathOffset = trimPathOffset;
1082e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui        }
1083e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui
10849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
10859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
10869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
10879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
10889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
10897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
10907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
10917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
10927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
10937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
10957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
1096e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
10977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
10987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
10997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
11007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
11017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
1102abb7d134c02ac60091108c491dafb00877093170John Hoford
11039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
11047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
11059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
11087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
1109abb7d134c02ac60091108c491dafb00877093170John Hoford            }
11109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
11137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
11147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
11157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
11197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
11207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1121abb7d134c02ac60091108c491dafb00877093170John Hoford            }
11229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
11257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
11267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
11277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
11309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
1131abb7d134c02ac60091108c491dafb00877093170John Hoford            }
11329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
11349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
11359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
11367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
11379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
11407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
11417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
11447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
11457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
11497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
11507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
11517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
11547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
11557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
11567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
11577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
11587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
11609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1161abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
1162abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1163abb7d134c02ac60091108c491dafb00877093170John Hoford
11649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
11659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
11669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
11679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
11699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
11709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
11719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
11740cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath);
11759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
11779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
1179e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui                mPathName = a.getString(R.styleable.VectorDrawablePath_name);
11809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
11837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
11849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
11859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
11867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
11877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
11887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
11897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
11907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
11917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
11927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
11937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
11947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
11957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
11967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
11977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
11987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
11997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
12007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
12017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
12027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
12037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
12047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
12059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
120763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui            a.recycle();
12089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
12099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
12119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
12122af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                mFillColor = applyAlpha(mFillColor, mFillOpacity);
12139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
12149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
12159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
12162af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui                mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity);
12179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
12189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
12199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1220abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
1221abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
1222abb7d134c02ac60091108c491dafb00877093170John Hoford
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
1224abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
1225abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
1226abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1229abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1230abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
1231abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1232abb7d134c02ac60091108c491dafb00877093170John Hoford
1233abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
1234abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
1235abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1236abb7d134c02ac60091108c491dafb00877093170John Hoford
1237abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1238abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
1239abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
1240abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
1241abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1242abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
1243abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
1244abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1245abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
1246abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
1247abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
1248abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1249abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
1250abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
1251abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
1252abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
1253abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
1254abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
1255abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
1256abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
1257abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
1258abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1259abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
1260abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
1261abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
1262abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1263abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
1264abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
1265abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
1266abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
1267abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1268abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1269abb7d134c02ac60091108c491dafb00877093170John Hoford
1270abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1271abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
1272abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
1273abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
1274abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
1275abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1276abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
1277abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
1278abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
1279abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
1280abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
1281abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1282abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
1283abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
1284abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1285abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
1286abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1287abb7d134c02ac60091108c491dafb00877093170John Hoford
1288abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
1289abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
1290abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
1291abb7d134c02ac60091108c491dafb00877093170John Hoford
1292abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
1293abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
1294abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
1295abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
1296abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
1297abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
1298abb7d134c02ac60091108c491dafb00877093170John Hoford
1299abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
1300abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
1301abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1302abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
1303abb7d134c02ac60091108c491dafb00877093170John Hoford
1304abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
1305abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1306abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
1307abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1308abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1309abb7d134c02ac60091108c491dafb00877093170John Hoford
1310abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
13115c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
13125c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
13139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1314abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
13155c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
13165c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
1317abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1318abb7d134c02ac60091108c491dafb00877093170John Hoford
1319abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
13205c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
13215c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
1322abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1323abb7d134c02ac60091108c491dafb00877093170John Hoford
1324abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
13255c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
132633ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
1327abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
132833ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
132933ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
1330abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1331abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1332abb7d134c02ac60091108c491dafb00877093170John Hoford
133333ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
133433ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
1335abb7d134c02ac60091108c491dafb00877093170John Hoford
1336abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
1337abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
1338abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
1339abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
1340abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
134133ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
134233ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
1343abb7d134c02ac60091108c491dafb00877093170John Hoford
1344abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
1345abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
1346abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
1347abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
1348abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
1349abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
1350abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
1351abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
1352abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
1353abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
1354abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
1355abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
1356abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1357abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
1358abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
1359abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
1360abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
1361abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
1362abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1363abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
1364abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
1365abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1366abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1367abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1368abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1369abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1370abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1371abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1372abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1373abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1374abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1375abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1376abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1377abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1378abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1379abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1380abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1381abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1382abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1383abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1384abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1385abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1386abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1387abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1388abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1389abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1390abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1391abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1392abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1393abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1394abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1395abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1396abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1397abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1398abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1399abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1400abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1401abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1402abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1403abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1404abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1405abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1406abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1407abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1408abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1409abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1410abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1411abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1412abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1413abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1414abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1415abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1416abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1417abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1418abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1419abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1420abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
142133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
142233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1423abb7d134c02ac60091108c491dafb00877093170John Hoford
1424abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1425abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1426abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1427abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1428abb7d134c02ac60091108c491dafb00877093170John Hoford
1429abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1430abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
143133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
143233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1433abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1434abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1435abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1436abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1437abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1438abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
143933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
144033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
144133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
144233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
144333ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
144433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
144533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
144633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1447abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1448abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1449abb7d134c02ac60091108c491dafb00877093170John Hoford
1450abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1451abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1452abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1453abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1454abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1455abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
145633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
145733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
145833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
145933ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
146033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
146133ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
146233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
146333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
146433ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1465abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1466abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
146733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
146833ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1469abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1470abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1471abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
147233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
147333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1474abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1475abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1476abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1477abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1478abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1479abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1480abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
148133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
148233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1483abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1484abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
148533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
148633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
148733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
148833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
148933ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
149033ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
149133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
149233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1493abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1494175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
1495175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
1496abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1497abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1498abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1499abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
150033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
150133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
150233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
150333ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
150433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
150533ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
150633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
150733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1508abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
150933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
151033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
1511abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
151233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
1513abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1514abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1515abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1516abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1517abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1518abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1519abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1520abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1521abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1522abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1523abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1524abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1525abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1526abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1527abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1528abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1529abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1530abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1531abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1532abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1533abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1534abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1535abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1536abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1537abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1538abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1539abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1540abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1541abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1542abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1543abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
1544abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1545abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1546abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1547abb7d134c02ac60091108c491dafb00877093170John Hoford                }
154833ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
1549abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1550abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
1551abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
1552abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
1553abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
1554abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1555abb7d134c02ac60091108c491dafb00877093170John Hoford
1556abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
1557abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
1558abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
1559abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
1560abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
1561abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
1562abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
1563abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
1564abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
1565abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
1566abb7d134c02ac60091108c491dafb00877093170John Hoford
1567abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
1568abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
1569abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
1570abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
1571abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
1572abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
1573abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
1574abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
1575abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
1576abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
1577abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
1578abb7d134c02ac60091108c491dafb00877093170John Hoford
1579abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
1580abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
1581abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
1582abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
1583abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
1584abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
1585abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
1586abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
1587abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
1588abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
1589abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1590abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
1591abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
1592abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
1593abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
1594abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
1595abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
1596abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
1597abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1598abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
1599abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
1600abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
1601abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
1602abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
1603abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
1604abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
1605abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
1606abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1607abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
1608abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
1609abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1610abb7d134c02ac60091108c491dafb00877093170John Hoford
1611abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
1612abb7d134c02ac60091108c491dafb00877093170John Hoford
1613abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
1614abb7d134c02ac60091108c491dafb00877093170John Hoford
1615abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
1616abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
1617abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
1618abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
1619abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1620abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
1621abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1622abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1623abb7d134c02ac60091108c491dafb00877093170John Hoford
1624abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
1625abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
1626abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
1627abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
1628abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
1629abb7d134c02ac60091108c491dafb00877093170John Hoford
1630abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
1631abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1632abb7d134c02ac60091108c491dafb00877093170John Hoford
1633abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1634abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
1635abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1636abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
1637abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
1638abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
1639abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
1640abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
1641abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
1642abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
1643abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
1644abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
1645abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
1646abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1647abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
1648abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
1649abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
1650abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
1651abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
1652abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
1653abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
1654abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
1655abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
1656abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
1657abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
1658abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
1659abb7d134c02ac60091108c491dafb00877093170John Hoford
1660abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
1661abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
1662abb7d134c02ac60091108c491dafb00877093170John Hoford
1663abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
1664abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
1665abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
1666abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
1667abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
1668abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
1669abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
1670abb7d134c02ac60091108c491dafb00877093170John Hoford
1671abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
1672abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
1673abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
1674abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
1675abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
1676abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
1677abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
1678abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
1679abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
1680abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
1681abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
1682abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
1683abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
1684abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
1685abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
1686abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
1687abb7d134c02ac60091108c491dafb00877093170John Hoford
1688abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
1689abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
1690abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
1691abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
1692abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
1693abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
1694abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
1695abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
1696abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
1697abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
1698abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
1699abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1700abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1701abb7d134c02ac60091108c491dafb00877093170John Hoford
1702abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1703abb7d134c02ac60091108c491dafb00877093170John Hoford}
1704