VectorDrawable.java revision ddbbb8ae8561c9e61becd03faa40997d76ab5a51
1abb7d134c02ac60091108c491dafb00877093170John Hoford/*
2abb7d134c02ac60091108c491dafb00877093170John Hoford * Copyright (C) 2014 The Android Open Source Project
3abb7d134c02ac60091108c491dafb00877093170John Hoford *
4abb7d134c02ac60091108c491dafb00877093170John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5abb7d134c02ac60091108c491dafb00877093170John Hoford * in compliance with the License. You may obtain a copy of the License at
6abb7d134c02ac60091108c491dafb00877093170John Hoford *
7abb7d134c02ac60091108c491dafb00877093170John Hoford * http://www.apache.org/licenses/LICENSE-2.0
8abb7d134c02ac60091108c491dafb00877093170John Hoford *
9abb7d134c02ac60091108c491dafb00877093170John Hoford * Unless required by applicable law or agreed to in writing, software distributed under the License
10abb7d134c02ac60091108c491dafb00877093170John Hoford * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11abb7d134c02ac60091108c491dafb00877093170John Hoford * or implied. See the License for the specific language governing permissions and limitations under
12abb7d134c02ac60091108c491dafb00877093170John Hoford * the License.
13abb7d134c02ac60091108c491dafb00877093170John Hoford */
14abb7d134c02ac60091108c491dafb00877093170John Hoford
15abb7d134c02ac60091108c491dafb00877093170John Hofordpackage android.graphics.drawable;
16abb7d134c02ac60091108c491dafb00877093170John Hoford
17abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources;
18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme;
194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray;
20abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas;
21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter;
22abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix;
23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint;
24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path;
25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure;
26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat;
27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect;
28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region;
29abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet;
30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log;
314b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport android.util.Xml;
32abb7d134c02ac60091108c491dafb00877093170John Hoford
33abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R;
34abb7d134c02ac60091108c491dafb00877093170John Hoford
35abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser;
36abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException;
374b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport org.xmlpull.v1.XmlPullParserFactory;
38abb7d134c02ac60091108c491dafb00877093170John Hoford
39abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException;
40abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList;
41abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays;
42abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Collection;
43abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap;
444b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
45abb7d134c02ac60091108c491dafb00877093170John Hoford/**
46d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be
47d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code>&lt;vector></code> element.
48abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
49abb7d134c02ac60091108c491dafb00877093170John Hoford * The vector drawable has 6 elements:
50abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
51abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
52177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
53fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:versionCode</code> defines the version of
54d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * VectorDrawable</dd>
55abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;size></code></dt>
56abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using
57d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:width</code> and <code>android:height</code></dd>
58abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;viewport></code></dt>
59abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
60d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * The size is defined using the attributes <code>android:viewportHeight</code>
61d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:viewportWidth</code></dd>
62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;group></code></dt>
63ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui * <dd>Defines the static 2D image.</dd>
64abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>&lt;path></code></dt>
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines paths to be drawn. The path elements must be within a group
66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
68abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
69abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
70abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines path string.</dd></dt>
71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
74d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd>
75d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
93d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end)
94d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
105abb7d134c02ac60091108c491dafb00877093170John Hoford */
106abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
109abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
110abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
111abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_GROUP = "group";
112abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
113abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
114abb7d134c02ac60091108c491dafb00877093170John Hoford
115abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
116abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
117abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
119abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
120abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
121abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
125abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
126abb7d134c02ac60091108c491dafb00877093170John Hoford
127abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
129abb7d134c02ac60091108c491dafb00877093170John Hoford    }
130abb7d134c02ac60091108c491dafb00877093170John Hoford
1319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
132abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
137abb7d134c02ac60091108c491dafb00877093170John Hoford    }
138abb7d134c02ac60091108c491dafb00877093170John Hoford
139abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
140abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
141abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
142abb7d134c02ac60091108c491dafb00877093170John Hoford    }
143abb7d134c02ac60091108c491dafb00877093170John Hoford
1444554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette    @Override
145abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
1484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
149ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
1504b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
151abb7d134c02ac60091108c491dafb00877093170John Hoford    }
152abb7d134c02ac60091108c491dafb00877093170John Hoford
153abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
154abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
155abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
156abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
157abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
158abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
159abb7d134c02ac60091108c491dafb00877093170John Hoford        }
160abb7d134c02ac60091108c491dafb00877093170John Hoford    }
161abb7d134c02ac60091108c491dafb00877093170John Hoford
162abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
163abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
164abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
165abb7d134c02ac60091108c491dafb00877093170John Hoford    }
166abb7d134c02ac60091108c491dafb00877093170John Hoford
167abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
168abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
169abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
170abb7d134c02ac60091108c491dafb00877093170John Hoford    }
171abb7d134c02ac60091108c491dafb00877093170John Hoford
172abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
173d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * Sets padding for this shape, defined by a Rect object. Define the padding
174d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * in the Rect object as: left, top, right, bottom.
175abb7d134c02ac60091108c491dafb00877093170John Hoford     */
176abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
177abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
178abb7d134c02ac60091108c491dafb00877093170John Hoford    }
179abb7d134c02ac60091108c491dafb00877093170John Hoford
180abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
181abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
182abb7d134c02ac60091108c491dafb00877093170John Hoford     *
183abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
184abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
185abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
186abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
187abb7d134c02ac60091108c491dafb00877093170John Hoford     */
188abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
189abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
190abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
191abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
192abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
193abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
194abb7d134c02ac60091108c491dafb00877093170John Hoford            }
195abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
196abb7d134c02ac60091108c491dafb00877093170John Hoford        }
197abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
198abb7d134c02ac60091108c491dafb00877093170John Hoford    }
199abb7d134c02ac60091108c491dafb00877093170John Hoford
200abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
201abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
202ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseWidth;
203abb7d134c02ac60091108c491dafb00877093170John Hoford    }
204abb7d134c02ac60091108c491dafb00877093170John Hoford
205abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
206abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
207ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseHeight;
208abb7d134c02ac60091108c491dafb00877093170John Hoford    }
209abb7d134c02ac60091108c491dafb00877093170John Hoford
210abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
211abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
212abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
213abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
214abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
215abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
216abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
217abb7d134c02ac60091108c491dafb00877093170John Hoford        }
218abb7d134c02ac60091108c491dafb00877093170John Hoford    }
219abb7d134c02ac60091108c491dafb00877093170John Hoford
220abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
221abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
222abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
223ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
224ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        setPathRenderer(p);
225abb7d134c02ac60091108c491dafb00877093170John Hoford    }
226abb7d134c02ac60091108c491dafb00877093170John Hoford
2279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
2299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
2309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
2349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
2359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
237ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer path = state.mVPathRenderer;
2389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
2399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
2409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
2419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2434b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    /** @hide */
2444b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    public static VectorDrawable create(Resources resources, int rid) {
2454b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        try {
2464b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParser xpp = resources.getXml(rid);
2474b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final AttributeSet attrs = Xml.asAttributeSet(xpp);
2484b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
2494b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            factory.setNamespaceAware(true);
2504b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
2514b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final VectorDrawable drawable = new VectorDrawable();
2524b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.inflate(resources, xpp, attrs);
2534b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
2544b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            return drawable;
2554b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (XmlPullParserException e) {
2564b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
2574b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (IOException e) {
2584b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
2594b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        }
2604b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        return null;
2614b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    }
2624b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
263ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
2649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
265ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer pathRenderer = new VPathRenderer();
2669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
267abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
268abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
269abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noGroupTag = true;
270abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
2719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        VGroup currentGroup = null;
273abb7d134c02ac60091108c491dafb00877093170John Hoford
274abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
275abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
276abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
2779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
278abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
2799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
2809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
2819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
282abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
283abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
284ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseSize(res, attrs);
285abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
286abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
287ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseViewport(res, attrs);
288abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
289abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_GROUP.equals(tagName)) {
2909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup = new VGroup();
291ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.mGroupList.add(currentGroup);
292abb7d134c02ac60091108c491dafb00877093170John Hoford                    noGroupTag = false;
293d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                } else if (SHAPE_VECTOR.equals(tagName)) {
2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
295177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
296177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Parsing the version information.
297177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Right now, we only support version "1".
298d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                    // If the xml didn't specify the version number, the default
299d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                    // version is "1".
3009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
301177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    if (versionCode != 1) {
302177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                        throw new IllegalArgumentException(
303177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                                "So far, VectorDrawable only support version 1");
304177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    }
305177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
306abb7d134c02ac60091108c491dafb00877093170John Hoford                    a.recycle();
307abb7d134c02ac60091108c491dafb00877093170John Hoford                }
308abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
310abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
311abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
313abb7d134c02ac60091108c491dafb00877093170John Hoford        if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
3149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
3159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
316abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
3179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
318abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
320d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noViewportTag) {
321d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
322abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
323abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
325abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
327d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noGroupTag) {
328d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
329abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
330abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_GROUP);
332abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
334d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noPathTag) {
335d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
336abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
337abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
339abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
342abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
344abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
345ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        pathRenderer.parseFinish();
346ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return pathRenderer;
347abb7d134c02ac60091108c491dafb00877093170John Hoford    }
348abb7d134c02ac60091108c491dafb00877093170John Hoford
349ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private void setPathRenderer(VPathRenderer pathRenderer) {
350ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer = pathRenderer;
351abb7d134c02ac60091108c491dafb00877093170John Hoford    }
352abb7d134c02ac60091108c491dafb00877093170John Hoford
3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
355ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        VPathRenderer mVPathRenderer;
3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
361ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
3695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
3735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
3745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
3785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
3795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3805c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3815c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3825c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
3835c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
3845c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3855c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
3865c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
387ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private static class VPathRenderer {
3884b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
3894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
3904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Matrix mMatrix = new Matrix();
3914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
392abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
3934b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
3944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
395abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
3964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
3979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
3989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
399abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
400abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
401abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
402abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
403abb7d134c02ac60091108c491dafb00877093170John Hoford
404ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer() {
405abb7d134c02ac60091108c491dafb00877093170John Hoford        }
4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
407ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer(VPathRenderer copy) {
4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mGroupList.addAll(copy.mGroupList);
409abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
410abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
411abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
412abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
413abb7d134c02ac60091108c491dafb00877093170John Hoford                }
414abb7d134c02ac60091108c491dafb00877093170John Hoford            }
415abb7d134c02ac60091108c491dafb00877093170John Hoford
416abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
417abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
418abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
419abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
420abb7d134c02ac60091108c491dafb00877093170John Hoford        }
421abb7d134c02ac60091108c491dafb00877093170John Hoford
4229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
4239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
4249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
4259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
4269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
4279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
4289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
4299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        return true;
4309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
4319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
4339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
4359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
4389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final ArrayList<VGroup> groups = mGroupList;
4399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            for (int i = groups.size() - 1; i >= 0; i--) {
4409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final ArrayList<VPath> paths = groups.get(i).mVGList;
4419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                for (int j = paths.size() - 1; j >= 0; j--) {
4429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = paths.get(j);
4439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    if (path.canApplyTheme()) {
4449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                        path.applyTheme(t);
4459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    }
4469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
4489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
449abb7d134c02ac60091108c491dafb00877093170John Hoford        }
450abb7d134c02ac60091108c491dafb00877093170John Hoford
4514b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        public void draw(Canvas canvas, int w, int h) {
452abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
453abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
454abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
455abb7d134c02ac60091108c491dafb00877093170John Hoford            }
456abb7d134c02ac60091108c491dafb00877093170John Hoford
457abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
458ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                if (mCurrentPaths[i] != null) {
459abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
460abb7d134c02ac60091108c491dafb00877093170John Hoford                }
461abb7d134c02ac60091108c491dafb00877093170John Hoford            }
462abb7d134c02ac60091108c491dafb00877093170John Hoford        }
463abb7d134c02ac60091108c491dafb00877093170John Hoford
464abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
4659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
466abb7d134c02ac60091108c491dafb00877093170John Hoford
467abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
4684b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final Path path = mPath;
469abb7d134c02ac60091108c491dafb00877093170John Hoford
470abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
471abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
472abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
473abb7d134c02ac60091108c491dafb00877093170John Hoford
474abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
475abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
476abb7d134c02ac60091108c491dafb00877093170John Hoford                }
477abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
478abb7d134c02ac60091108c491dafb00877093170John Hoford
479abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
480abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
481abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
482abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
483abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
484abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
485abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
486abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
487abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
488abb7d134c02ac60091108c491dafb00877093170John Hoford                }
489abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
490abb7d134c02ac60091108c491dafb00877093170John Hoford            }
491abb7d134c02ac60091108c491dafb00877093170John Hoford
492abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
493abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
494abb7d134c02ac60091108c491dafb00877093170John Hoford
495abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
496abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
497abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
498abb7d134c02ac60091108c491dafb00877093170John Hoford
499abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
500abb7d134c02ac60091108c491dafb00877093170John Hoford
501abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
502abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
503abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
505abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
5064b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mFillPaint == null) {
5074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint = new Paint();
5084b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setStyle(Paint.Style.FILL);
5094b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setAntiAlias(true);
5104b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
5114b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
512abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
513abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
514abb7d134c02ac60091108c491dafb00877093170John Hoford            }
5159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
516abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
5174b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mStrokePaint == null) {
5184b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint = new Paint();
5194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setStyle(Paint.Style.STROKE);
5204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setAntiAlias(true);
5214b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
5224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                final Paint strokePaint = mStrokePaint;
5247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineJoin != null) {
5254b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
526abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5274b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineCap != null) {
5294b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
530abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5314b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5324b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
5334b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setColor(vPath.mStrokeColor);
5344b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
5354b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                canvas.drawPath(mRenderPath, strokePaint);
536abb7d134c02ac60091108c491dafb00877093170John Hoford            }
537abb7d134c02ac60091108c491dafb00877093170John Hoford        }
538abb7d134c02ac60091108c491dafb00877093170John Hoford
539abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
540abb7d134c02ac60091108c491dafb00877093170John Hoford         * Build the "current" path based on the first group
541abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
542abb7d134c02ac60091108c491dafb00877093170John Hoford         */
543abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
5449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final Collection<VPath> paths = mGroupList.get(0).getPaths();
545abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
546abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
547abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
548abb7d134c02ac60091108c491dafb00877093170John Hoford            }
549abb7d134c02ac60091108c491dafb00877093170John Hoford        }
550abb7d134c02ac60091108c491dafb00877093170John Hoford
551abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
552abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
5534b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
554abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
555abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
556abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
557abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
558abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
559abb7d134c02ac60091108c491dafb00877093170John Hoford            }
560abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
561abb7d134c02ac60091108c491dafb00877093170John Hoford        }
562abb7d134c02ac60091108c491dafb00877093170John Hoford
563abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
564abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
5654b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
566abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
567abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
568abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
569abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
570abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
571abb7d134c02ac60091108c491dafb00877093170John Hoford            }
572abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
573abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
575abb7d134c02ac60091108c491dafb00877093170John Hoford    }
576abb7d134c02ac60091108c491dafb00877093170John Hoford
577abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
5789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
5799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
580abb7d134c02ac60091108c491dafb00877093170John Hoford
581abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
582abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
583abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
584abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
585abb7d134c02ac60091108c491dafb00877093170John Hoford         }
586abb7d134c02ac60091108c491dafb00877093170John Hoford
587abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
588abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
589abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
590abb7d134c02ac60091108c491dafb00877093170John Hoford         */
591abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
592abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
593abb7d134c02ac60091108c491dafb00877093170John Hoford        }
594abb7d134c02ac60091108c491dafb00877093170John Hoford
595abb7d134c02ac60091108c491dafb00877093170John Hoford    }
596abb7d134c02ac60091108c491dafb00877093170John Hoford
597abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
598abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
5999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
6019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
602abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
603abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
604abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
6059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
606abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
607abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
608abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
6099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
610abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
611abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
612abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
6139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
614abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
615abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
616abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
6179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
618abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
6194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
6204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
621abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
6229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
6249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
625abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
626abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
627abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
628abb7d134c02ac60091108c491dafb00877093170John Hoford
6299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
6309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
6319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
6349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
6359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
637abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
638abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
639abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
640abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
641abb7d134c02ac60091108c491dafb00877093170John Hoford            }
642abb7d134c02ac60091108c491dafb00877093170John Hoford        }
643abb7d134c02ac60091108c491dafb00877093170John Hoford
6447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
645abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
646abb7d134c02ac60091108c491dafb00877093170John Hoford        }
647abb7d134c02ac60091108c491dafb00877093170John Hoford
6487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
6497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
6517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
6527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
6537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
6547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
6557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
6567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
6627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
6647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
6657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
6667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
6677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
6687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
6697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
6779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
6789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
6807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
6827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
6837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
6877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
6907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
6917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
692abb7d134c02ac60091108c491dafb00877093170John Hoford
6939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
6959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
699abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
7027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
7037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
7067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
707abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
7107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
7117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
7157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
7167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
7177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
7217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
7227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
723abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
7277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
7287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
7329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
733abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
7369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
7379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
7399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
7427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
7437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
7467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
7477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
7517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
7527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
7537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
7577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
7587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
7597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
7629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
763abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
764abb7d134c02ac60091108c491dafb00877093170John Hoford        }
765abb7d134c02ac60091108c491dafb00877093170John Hoford
7669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
7679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
7689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
7719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
7729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
7739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
7769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
7779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
7799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
7817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
7829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
7857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
7869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
7897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
7907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
7927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
7937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
7947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
7967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
7977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
7987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
7997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
8007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
8017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
8027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
8037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
8047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
8057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
8067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
8077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
8087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
8097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
8107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
8119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
8139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
8149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
8169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
8179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
8189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
8199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
8229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
8239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
8249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
8269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
827abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
828abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
829abb7d134c02ac60091108c491dafb00877093170John Hoford
830abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
831abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
832abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
833abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
834abb7d134c02ac60091108c491dafb00877093170John Hoford                }
835abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
836abb7d134c02ac60091108c491dafb00877093170John Hoford            }
837abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
838abb7d134c02ac60091108c491dafb00877093170John Hoford        }
839abb7d134c02ac60091108c491dafb00877093170John Hoford
840abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
841abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
842abb7d134c02ac60091108c491dafb00877093170John Hoford        }
843abb7d134c02ac60091108c491dafb00877093170John Hoford
844abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
845abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
846abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
847abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
848abb7d134c02ac60091108c491dafb00877093170John Hoford         *
849abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
850abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
851abb7d134c02ac60091108c491dafb00877093170John Hoford         */
852abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
853abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
854abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
855abb7d134c02ac60091108c491dafb00877093170John Hoford            }
856abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
857abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
858abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
859abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
860abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
861abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
862abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
863abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
864abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
865abb7d134c02ac60091108c491dafb00877093170John Hoford                }
866abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
867abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
868abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
869abb7d134c02ac60091108c491dafb00877093170John Hoford                }
870abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
871abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
872abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
873abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
874abb7d134c02ac60091108c491dafb00877093170John Hoford            }
875abb7d134c02ac60091108c491dafb00877093170John Hoford        }
876abb7d134c02ac60091108c491dafb00877093170John Hoford
877abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
878abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
879abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
880abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
881abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
882abb7d134c02ac60091108c491dafb00877093170John Hoford         */
883abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
884abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
885abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
886abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
887abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
888abb7d134c02ac60091108c491dafb00877093170John Hoford            }
889abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
890abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
891abb7d134c02ac60091108c491dafb00877093170John Hoford            }
892abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
893abb7d134c02ac60091108c491dafb00877093170John Hoford        }
894abb7d134c02ac60091108c491dafb00877093170John Hoford
895abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
896abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
897abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
898abb7d134c02ac60091108c491dafb00877093170John Hoford
899abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
900abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
901abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
902abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
903abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
904abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
905abb7d134c02ac60091108c491dafb00877093170John Hoford
906abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
907abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
908abb7d134c02ac60091108c491dafb00877093170John Hoford            }
909abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
910abb7d134c02ac60091108c491dafb00877093170John Hoford
911abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
912abb7d134c02ac60091108c491dafb00877093170John Hoford            }
913abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
914abb7d134c02ac60091108c491dafb00877093170John Hoford        }
915abb7d134c02ac60091108c491dafb00877093170John Hoford
916abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
917abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
918abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
919abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
920abb7d134c02ac60091108c491dafb00877093170John Hoford            }
921abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
922abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
923abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
924abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
925abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
926abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
927abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
928abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
929abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
930abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
9317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = p1.mStrokeLineCap;
9327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = p1.mStrokeLineJoin;
933abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
934abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
935abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
936abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
937abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
938abb7d134c02ac60091108c491dafb00877093170John Hoford            }
939abb7d134c02ac60091108c491dafb00877093170John Hoford
940abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
941abb7d134c02ac60091108c491dafb00877093170John Hoford        }
942abb7d134c02ac60091108c491dafb00877093170John Hoford    }
943abb7d134c02ac60091108c491dafb00877093170John Hoford
944abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
9455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
9465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
9479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
948abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
9495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
9505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
951abb7d134c02ac60091108c491dafb00877093170John Hoford        }
952abb7d134c02ac60091108c491dafb00877093170John Hoford
953abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
9545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
9555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
956abb7d134c02ac60091108c491dafb00877093170John Hoford        }
957abb7d134c02ac60091108c491dafb00877093170John Hoford
958abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
9595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
96033ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
961abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
96233ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
96333ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
964abb7d134c02ac60091108c491dafb00877093170John Hoford            }
965abb7d134c02ac60091108c491dafb00877093170John Hoford        }
966abb7d134c02ac60091108c491dafb00877093170John Hoford
96733ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
96833ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
969abb7d134c02ac60091108c491dafb00877093170John Hoford
970abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
971abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
972abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
973abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
974abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
97533ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
97633ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
977abb7d134c02ac60091108c491dafb00877093170John Hoford
978abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
979abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
980abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
981abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
982abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
983abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
984abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
985abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
986abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
987abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
988abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
989abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
990abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
991abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
992abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
993abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
994abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
995abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
996abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
997abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
998abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
999abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
1000abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
1002abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
1003abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
1004abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
1005abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
1006abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1007abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
1008abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
1009abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
1010abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
1011abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1012abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
1013abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
1014abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
1015abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
1016abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1017abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1018abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1019abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1020abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1021abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1022abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1023abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1024abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1025abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1026abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1027abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1028abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1029abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1030abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1031abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1032abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1033abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1034abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1035abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1036abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1037abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1038abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1039abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1040abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1041abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1042abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1043abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1044abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1045abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1046abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1047abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1048abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1049abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1050abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1051abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1052abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1053abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1054abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
105533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
105633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1057abb7d134c02ac60091108c491dafb00877093170John Hoford
1058abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1059abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1060abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1061abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1062abb7d134c02ac60091108c491dafb00877093170John Hoford
1063abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1064abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
106533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
106633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1067abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1068abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1069abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1070abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1071abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1072abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
107333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
107433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
107533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
107633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
107733ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
107833ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
107933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
108033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1081abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1082abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1083abb7d134c02ac60091108c491dafb00877093170John Hoford
1084abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1085abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1086abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1087abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1088abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1089abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
109033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
109133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
109233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
109333ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
109433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
109533ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
109633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
109733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
109833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1099abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1100abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
110133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
110233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1103abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1104abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1105abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
110633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
110733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1108abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1109abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1110abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1111abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1112abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1113abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1114abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
111533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
111633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1117abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1118abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
111933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
112033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
112133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
112233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
112333ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
112433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
112533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
112633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1127abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1128175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
1129175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
1130abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1131abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1132abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1133abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
113433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
113533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
113633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
113733ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
113833ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
113933ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
114033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
114133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1142abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
114333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
114433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
1145abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
114633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
1147abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1148abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1149abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1150abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1151abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1152abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1153abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1154abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1155abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1156abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1157abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1159abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1160abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1161abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1162abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1163abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1164abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1165abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1166abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1167abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1168abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1169abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1170abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1171abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1172abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1173abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1174abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1175abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1176abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1177abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
1178abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1179abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1180abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1181abb7d134c02ac60091108c491dafb00877093170John Hoford                }
118233ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
1183abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1184abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
1185abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
1186abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
1187abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
1188abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1189abb7d134c02ac60091108c491dafb00877093170John Hoford
1190abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
1191abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
1192abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
1193abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
1194abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
1195abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
1196abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
1197abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
1198abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
1199abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
1200abb7d134c02ac60091108c491dafb00877093170John Hoford
1201abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
1202abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
1203abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
1204abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
1205abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
1206abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
1207abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
1208abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
1209abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
1210abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
1211abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
1212abb7d134c02ac60091108c491dafb00877093170John Hoford
1213abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
1214abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
1215abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
1216abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
1217abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
1218abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
1219abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
1220abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
1221abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
1222abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1224abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
1225abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
1226abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
1227abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
1228abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
1229abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
1230abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
1231abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1232abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
1233abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
1234abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
1235abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
1236abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
1237abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
1238abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
1239abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
1240abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1241abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
1242abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
1243abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1244abb7d134c02ac60091108c491dafb00877093170John Hoford
1245abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
1246abb7d134c02ac60091108c491dafb00877093170John Hoford
1247abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
1248abb7d134c02ac60091108c491dafb00877093170John Hoford
1249abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
1250abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
1251abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
1252abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
1253abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1254abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
1255abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1256abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1257abb7d134c02ac60091108c491dafb00877093170John Hoford
1258abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
1259abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
1260abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
1261abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
1262abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
1263abb7d134c02ac60091108c491dafb00877093170John Hoford
1264abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
1265abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1266abb7d134c02ac60091108c491dafb00877093170John Hoford
1267abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1268abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
1269abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1270abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
1271abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
1272abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
1273abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
1274abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
1275abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
1276abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
1277abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
1278abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
1279abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
1280abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1281abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
1282abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
1283abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
1284abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
1285abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
1286abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
1287abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
1288abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
1289abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
1290abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
1291abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
1292abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
1293abb7d134c02ac60091108c491dafb00877093170John Hoford
1294abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
1295abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
1296abb7d134c02ac60091108c491dafb00877093170John Hoford
1297abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
1298abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
1299abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
1300abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
1301abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
1302abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
1303abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
1304abb7d134c02ac60091108c491dafb00877093170John Hoford
1305abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
1306abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
1307abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
1308abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
1309abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
1310abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
1311abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
1312abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
1313abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
1314abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
1315abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
1316abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
1317abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
1318abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
1319abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
1320abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
1321abb7d134c02ac60091108c491dafb00877093170John Hoford
1322abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
1323abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
1324abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
1325abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
1326abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
1327abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
1328abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
1329abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
1330abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
1331abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
1332abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
1333abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1334abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1335abb7d134c02ac60091108c491dafb00877093170John Hoford
1336abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1337abb7d134c02ac60091108c491dafb00877093170John Hoford}
1338