VectorDrawable.java revision 46e546c28fd52b4dedf0a0fbd313db589cb9048b
1abb7d134c02ac60091108c491dafb00877093170John Hoford/*
2abb7d134c02ac60091108c491dafb00877093170John Hoford * Copyright (C) 2014 The Android Open Source Project
3abb7d134c02ac60091108c491dafb00877093170John Hoford *
4abb7d134c02ac60091108c491dafb00877093170John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5abb7d134c02ac60091108c491dafb00877093170John Hoford * in compliance with the License. You may obtain a copy of the License at
6abb7d134c02ac60091108c491dafb00877093170John Hoford *
7abb7d134c02ac60091108c491dafb00877093170John Hoford * http://www.apache.org/licenses/LICENSE-2.0
8abb7d134c02ac60091108c491dafb00877093170John Hoford *
9abb7d134c02ac60091108c491dafb00877093170John Hoford * Unless required by applicable law or agreed to in writing, software distributed under the License
10abb7d134c02ac60091108c491dafb00877093170John Hoford * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11abb7d134c02ac60091108c491dafb00877093170John Hoford * or implied. See the License for the specific language governing permissions and limitations under
12abb7d134c02ac60091108c491dafb00877093170John Hoford * the License.
13abb7d134c02ac60091108c491dafb00877093170John Hoford */
14abb7d134c02ac60091108c491dafb00877093170John Hoford
15abb7d134c02ac60091108c491dafb00877093170John Hofordpackage android.graphics.drawable;
16abb7d134c02ac60091108c491dafb00877093170John Hoford
17abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources;
18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme;
194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray;
20abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas;
21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter;
22abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix;
23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint;
24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path;
25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure;
26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat;
27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect;
28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region;
29abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet;
30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log;
314b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport android.util.Xml;
32abb7d134c02ac60091108c491dafb00877093170John Hoford
33abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R;
34abb7d134c02ac60091108c491dafb00877093170John Hoford
35abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser;
36abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException;
374b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport org.xmlpull.v1.XmlPullParserFactory;
38abb7d134c02ac60091108c491dafb00877093170John Hoford
39abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException;
40abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList;
41abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays;
42abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Collection;
43abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap;
444b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
45abb7d134c02ac60091108c491dafb00877093170John Hoford/**
46d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be
47d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code>&lt;vector></code> element.
48abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
4946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The vector drawable has the following elements:
50abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/>
51abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
52177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code>&lt;vector></code></dt>
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;path></code></dt>
6346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines paths to be drawn. Multiple paths can be defined in one xml file.
6446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The paths are drawn in the order of their definition order.
65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl>
66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code>
67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt>
68abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code>
6946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines path string. This is using exactly same format as "d" attribute
7046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * in the SVG's path data</dd></dt>
71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code>
72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt>
73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code>
74d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd>
75d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt>
76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code>
77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt>
78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code>
79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt>
80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code>
81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt>
82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code>
83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt>
84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code>
85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code>
87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt>
88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code>
89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt>
90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code>
91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt>
92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code>
93d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end)
94d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt>
95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code>
96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt>
97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code>
98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt>
99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code>
100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code>
102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt>
103abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl>
104abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd>
105abb7d134c02ac60091108c491dafb00877093170John Hoford */
106abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable {
1079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
1089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
109abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_SIZE = "size";
110abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VIEWPORT = "viewport";
111abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_PATH = "path";
112abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final String SHAPE_VECTOR = "vector";
113abb7d134c02ac60091108c491dafb00877093170John Hoford
114abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_BUTT = 0;
115abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_ROUND = 1;
116abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINECAP_SQUARE = 2;
1179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
118abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_MITER = 0;
119abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_ROUND = 1;
120abb7d134c02ac60091108c491dafb00877093170John Hoford    private static final int LINEJOIN_BEVEL = 2;
1219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette    private final VectorDrawableState mVectorState;
1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
124abb7d134c02ac60091108c491dafb00877093170John Hoford    private int mAlpha = 0xFF;
125abb7d134c02ac60091108c491dafb00877093170John Hoford
126abb7d134c02ac60091108c491dafb00877093170John Hoford    public VectorDrawable() {
1279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        mVectorState = new VectorDrawableState(null);
128abb7d134c02ac60091108c491dafb00877093170John Hoford    }
129abb7d134c02ac60091108c491dafb00877093170John Hoford
1309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
131abb7d134c02ac60091108c491dafb00877093170John Hoford        mVectorState = new VectorDrawableState(state);
1329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (theme != null && canApplyTheme()) {
1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            applyTheme(theme);
1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
136abb7d134c02ac60091108c491dafb00877093170John Hoford    }
137abb7d134c02ac60091108c491dafb00877093170John Hoford
138abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
139abb7d134c02ac60091108c491dafb00877093170John Hoford    public ConstantState getConstantState() {
140abb7d134c02ac60091108c491dafb00877093170John Hoford        return mVectorState;
141abb7d134c02ac60091108c491dafb00877093170John Hoford    }
142abb7d134c02ac60091108c491dafb00877093170John Hoford
1434554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette    @Override
144abb7d134c02ac60091108c491dafb00877093170John Hoford    public void draw(Canvas canvas) {
1454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final int saveCount = canvas.save();
1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        final Rect bounds = getBounds();
1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.translate(bounds.left, bounds.top);
148ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
1494b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        canvas.restoreToCount(saveCount);
150abb7d134c02ac60091108c491dafb00877093170John Hoford    }
151abb7d134c02ac60091108c491dafb00877093170John Hoford
152abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
153abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setAlpha(int alpha) {
154abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO correct handling of transparent
155abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mAlpha != alpha) {
156abb7d134c02ac60091108c491dafb00877093170John Hoford            mAlpha = alpha;
157abb7d134c02ac60091108c491dafb00877093170John Hoford            invalidateSelf();
158abb7d134c02ac60091108c491dafb00877093170John Hoford        }
159abb7d134c02ac60091108c491dafb00877093170John Hoford    }
160abb7d134c02ac60091108c491dafb00877093170John Hoford
161abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
162abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setColorFilter(ColorFilter colorFilter) {
163abb7d134c02ac60091108c491dafb00877093170John Hoford        // TODO: support color filter
164abb7d134c02ac60091108c491dafb00877093170John Hoford    }
165abb7d134c02ac60091108c491dafb00877093170John Hoford
166abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
167abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getOpacity() {
168abb7d134c02ac60091108c491dafb00877093170John Hoford        return PixelFormat.TRANSLUCENT;
169abb7d134c02ac60091108c491dafb00877093170John Hoford    }
170abb7d134c02ac60091108c491dafb00877093170John Hoford
171abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
172d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * Sets padding for this shape, defined by a Rect object. Define the padding
173d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette     * in the Rect object as: left, top, right, bottom.
174abb7d134c02ac60091108c491dafb00877093170John Hoford     */
175abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(Rect padding) {
176abb7d134c02ac60091108c491dafb00877093170John Hoford        setPadding(padding.left, padding.top, padding.right, padding.bottom);
177abb7d134c02ac60091108c491dafb00877093170John Hoford    }
178abb7d134c02ac60091108c491dafb00877093170John Hoford
179abb7d134c02ac60091108c491dafb00877093170John Hoford    /**
180abb7d134c02ac60091108c491dafb00877093170John Hoford     * Sets padding for the shape.
181abb7d134c02ac60091108c491dafb00877093170John Hoford     *
182abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param left padding for the left side (in pixels)
183abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param top padding for the top (in pixels)
184abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param right padding for the right side (in pixels)
185abb7d134c02ac60091108c491dafb00877093170John Hoford     * @param bottom padding for the bottom (in pixels)
186abb7d134c02ac60091108c491dafb00877093170John Hoford     */
187abb7d134c02ac60091108c491dafb00877093170John Hoford    public void setPadding(int left, int top, int right, int bottom) {
188abb7d134c02ac60091108c491dafb00877093170John Hoford        if ((left | top | right | bottom) == 0) {
189abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding = null;
190abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
191abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mVectorState.mPadding == null) {
192abb7d134c02ac60091108c491dafb00877093170John Hoford                mVectorState.mPadding = new Rect();
193abb7d134c02ac60091108c491dafb00877093170John Hoford            }
194abb7d134c02ac60091108c491dafb00877093170John Hoford            mVectorState.mPadding.set(left, top, right, bottom);
195abb7d134c02ac60091108c491dafb00877093170John Hoford        }
196abb7d134c02ac60091108c491dafb00877093170John Hoford        invalidateSelf();
197abb7d134c02ac60091108c491dafb00877093170John Hoford    }
198abb7d134c02ac60091108c491dafb00877093170John Hoford
199abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
200abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicWidth() {
201ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseWidth;
202abb7d134c02ac60091108c491dafb00877093170John Hoford    }
203abb7d134c02ac60091108c491dafb00877093170John Hoford
204abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
205abb7d134c02ac60091108c491dafb00877093170John Hoford    public int getIntrinsicHeight() {
206ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return (int) mVectorState.mVPathRenderer.mBaseHeight;
207abb7d134c02ac60091108c491dafb00877093170John Hoford    }
208abb7d134c02ac60091108c491dafb00877093170John Hoford
209abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
210abb7d134c02ac60091108c491dafb00877093170John Hoford    public boolean getPadding(Rect padding) {
211abb7d134c02ac60091108c491dafb00877093170John Hoford        if (mVectorState.mPadding != null) {
212abb7d134c02ac60091108c491dafb00877093170John Hoford            padding.set(mVectorState.mPadding);
213abb7d134c02ac60091108c491dafb00877093170John Hoford            return true;
214abb7d134c02ac60091108c491dafb00877093170John Hoford        } else {
215abb7d134c02ac60091108c491dafb00877093170John Hoford            return super.getPadding(padding);
216abb7d134c02ac60091108c491dafb00877093170John Hoford        }
217abb7d134c02ac60091108c491dafb00877093170John Hoford    }
218abb7d134c02ac60091108c491dafb00877093170John Hoford
219abb7d134c02ac60091108c491dafb00877093170John Hoford    @Override
220abb7d134c02ac60091108c491dafb00877093170John Hoford    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
221abb7d134c02ac60091108c491dafb00877093170John Hoford            throws XmlPullParserException, IOException {
222ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
223ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        setPathRenderer(p);
224abb7d134c02ac60091108c491dafb00877093170John Hoford    }
225abb7d134c02ac60091108c491dafb00877093170John Hoford
2269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public boolean canApplyTheme() {
2289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
2299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    @Override
2329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    public void applyTheme(Theme t) {
2339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        super.applyTheme(t);
2349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        final VectorDrawableState state = mVectorState;
236ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer path = state.mVPathRenderer;
2379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        if (path != null && path.canApplyTheme()) {
2389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            path.applyTheme(t);
2399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
2409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette    }
2419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
2424b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    /** @hide */
2434b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    public static VectorDrawable create(Resources resources, int rid) {
2444b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        try {
2454b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParser xpp = resources.getXml(rid);
2464b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final AttributeSet attrs = Xml.asAttributeSet(xpp);
2474b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
2484b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            factory.setNamespaceAware(true);
2494b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
2504b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            final VectorDrawable drawable = new VectorDrawable();
2514b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            drawable.inflate(resources, xpp, attrs);
2524b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
2534b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            return drawable;
2544b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (XmlPullParserException e) {
2554b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
2564b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        } catch (IOException e) {
2574b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette            Log.e(LOGTAG, "parser error", e);
2584b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        }
2594b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette        return null;
2604b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette    }
2614b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette
262ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
2639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
264ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        final VPathRenderer pathRenderer = new VPathRenderer();
2659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
266abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noSizeTag = true;
267abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noViewportTag = true;
268abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean noPathTag = true;
2699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
27046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        VGroup currentGroup = new VGroup();
271abb7d134c02ac60091108c491dafb00877093170John Hoford
272abb7d134c02ac60091108c491dafb00877093170John Hoford        int eventType = parser.getEventType();
273abb7d134c02ac60091108c491dafb00877093170John Hoford        while (eventType != XmlPullParser.END_DOCUMENT) {
274abb7d134c02ac60091108c491dafb00877093170John Hoford            if (eventType == XmlPullParser.START_TAG) {
2759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                final String tagName = parser.getName();
276abb7d134c02ac60091108c491dafb00877093170John Hoford                if (SHAPE_PATH.equals(tagName)) {
2779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final VPath path = new VPath();
2789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    path.inflate(res, attrs, theme);
2799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    currentGroup.add(path);
280abb7d134c02ac60091108c491dafb00877093170John Hoford                    noPathTag = false;
281abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_SIZE.equals(tagName)) {
282ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseSize(res, attrs);
283abb7d134c02ac60091108c491dafb00877093170John Hoford                    noSizeTag = false;
284abb7d134c02ac60091108c491dafb00877093170John Hoford                } else if (SHAPE_VIEWPORT.equals(tagName)) {
285ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                    pathRenderer.parseViewport(res, attrs);
286abb7d134c02ac60091108c491dafb00877093170John Hoford                    noViewportTag = false;
287d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                } else if (SHAPE_VECTOR.equals(tagName)) {
2889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
289177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
290177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Parsing the version information.
291177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    // Right now, we only support version "1".
292d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                    // If the xml didn't specify the version number, the default
293d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                    // version is "1".
2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
295177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    if (versionCode != 1) {
296177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                        throw new IllegalArgumentException(
297177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                                "So far, VectorDrawable only support version 1");
298177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui                    }
299177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui
300abb7d134c02ac60091108c491dafb00877093170John Hoford                    a.recycle();
301abb7d134c02ac60091108c491dafb00877093170John Hoford                }
302abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
304abb7d134c02ac60091108c491dafb00877093170John Hoford            eventType = parser.next();
305abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
30746e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        if (noSizeTag || noViewportTag || noPathTag) {
3089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final StringBuffer tag = new StringBuffer();
3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
310abb7d134c02ac60091108c491dafb00877093170John Hoford            if (noSizeTag) {
3119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
312abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
314d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noViewportTag) {
315d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
316abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" & ");
317abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_SIZE);
319abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
321d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette            if (noPathTag) {
322d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette                if (tag.length() > 0) {
323abb7d134c02ac60091108c491dafb00877093170John Hoford                    tag.append(" or ");
324abb7d134c02ac60091108c491dafb00877093170John Hoford                }
3259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                tag.append(SHAPE_PATH);
326abb7d134c02ac60091108c491dafb00877093170John Hoford            }
3279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
3289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            throw new XmlPullParserException("no " + tag + " defined");
329abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
33146e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        pathRenderer.mCurrentGroup = currentGroup;
332abb7d134c02ac60091108c491dafb00877093170John Hoford        // post parse cleanup
333ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        pathRenderer.parseFinish();
334ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        return pathRenderer;
335abb7d134c02ac60091108c491dafb00877093170John Hoford    }
336abb7d134c02ac60091108c491dafb00877093170John Hoford
337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private void setPathRenderer(VPathRenderer pathRenderer) {
338ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        mVectorState.mVPathRenderer = pathRenderer;
339abb7d134c02ac60091108c491dafb00877093170John Hoford    }
340abb7d134c02ac60091108c491dafb00877093170John Hoford
3415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    private static class VectorDrawableState extends ConstantState {
3425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        int mChangingConfigurations;
343ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        VPathRenderer mVPathRenderer;
3445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        Rect mPadding;
3455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public VectorDrawableState(VectorDrawableState copy) {
3475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            if (copy != null) {
3485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mChangingConfigurations = copy.mChangingConfigurations;
349ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
3505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette                mPadding = new Rect(copy.mPadding);
3515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            }
3525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable() {
3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, null, null);
3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res) {
3615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, null);
3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public Drawable newDrawable(Resources res, Theme theme) {
3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return new VectorDrawable(this, res, theme);
3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
3695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        @Override
3705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        public int getChangingConfigurations() {
3715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            return mChangingConfigurations;
3725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        }
3735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette    }
3745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette
375ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui    private static class VPathRenderer {
3764b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mPath = new Path();
3774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Path mRenderPath = new Path();
3784b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private final Matrix mMatrix = new Matrix();
3794b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
380abb7d134c02ac60091108c491dafb00877093170John Hoford        private VPath[] mCurrentPaths;
3814b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mStrokePaint;
3824b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        private Paint mFillPaint;
383abb7d134c02ac60091108c491dafb00877093170John Hoford        private PathMeasure mPathMeasure;
3844b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
38546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui        private VGroup mCurrentGroup = new VGroup();
3869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
387abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseWidth = 1;
388abb7d134c02ac60091108c491dafb00877093170John Hoford        float mBaseHeight = 1;
389abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportWidth;
390abb7d134c02ac60091108c491dafb00877093170John Hoford        float mViewportHeight;
391abb7d134c02ac60091108c491dafb00877093170John Hoford
392ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer() {
393abb7d134c02ac60091108c491dafb00877093170John Hoford        }
3949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
395ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui        public VPathRenderer(VPathRenderer copy) {
39646e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui            mCurrentGroup = copy.mCurrentGroup;
397abb7d134c02ac60091108c491dafb00877093170John Hoford            if (copy.mCurrentPaths != null) {
398abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths = new VPath[copy.mCurrentPaths.length];
399abb7d134c02ac60091108c491dafb00877093170John Hoford                for (int i = 0; i < mCurrentPaths.length; i++) {
400abb7d134c02ac60091108c491dafb00877093170John Hoford                    mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
401abb7d134c02ac60091108c491dafb00877093170John Hoford                }
402abb7d134c02ac60091108c491dafb00877093170John Hoford            }
403abb7d134c02ac60091108c491dafb00877093170John Hoford
404abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = copy.mBaseWidth;
405abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = copy.mBaseHeight;
406abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = copy.mViewportHeight;
407abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = copy.mViewportHeight;
408abb7d134c02ac60091108c491dafb00877093170John Hoford        }
409abb7d134c02ac60091108c491dafb00877093170John Hoford
4109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
41146e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui            final ArrayList<VPath> paths = mCurrentGroup.mVGList;
41246e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui            for (int j = paths.size() - 1; j >= 0; j--) {
41346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui                final VPath path = paths.get(j);
41446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui                if (path.canApplyTheme()) {
41546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui                    return true;
4169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
4189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return false;
4199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
4209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
4219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
42246e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui            final ArrayList<VPath> paths = mCurrentGroup.mVGList;
42346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui            for (int j = paths.size() - 1; j >= 0; j--) {
42446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui                final VPath path = paths.get(j);
42546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui                if (path.canApplyTheme()) {
42646e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui                    path.applyTheme(t);
4279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                }
4289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
429abb7d134c02ac60091108c491dafb00877093170John Hoford        }
430abb7d134c02ac60091108c491dafb00877093170John Hoford
4314b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        public void draw(Canvas canvas, int w, int h) {
432abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mCurrentPaths == null) {
433abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"mCurrentPaths == null");
434abb7d134c02ac60091108c491dafb00877093170John Hoford                return;
435abb7d134c02ac60091108c491dafb00877093170John Hoford            }
436abb7d134c02ac60091108c491dafb00877093170John Hoford
437abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
438ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui                if (mCurrentPaths[i] != null) {
439abb7d134c02ac60091108c491dafb00877093170John Hoford                    drawPath(mCurrentPaths[i], canvas, w, h);
440abb7d134c02ac60091108c491dafb00877093170John Hoford                }
441abb7d134c02ac60091108c491dafb00877093170John Hoford            }
442abb7d134c02ac60091108c491dafb00877093170John Hoford        }
443abb7d134c02ac60091108c491dafb00877093170John Hoford
444abb7d134c02ac60091108c491dafb00877093170John Hoford        private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
4459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
446abb7d134c02ac60091108c491dafb00877093170John Hoford
447abb7d134c02ac60091108c491dafb00877093170John Hoford            vPath.toPath(mPath);
4484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final Path path = mPath;
449abb7d134c02ac60091108c491dafb00877093170John Hoford
450abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
451abb7d134c02ac60091108c491dafb00877093170John Hoford                float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
452abb7d134c02ac60091108c491dafb00877093170John Hoford                float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
453abb7d134c02ac60091108c491dafb00877093170John Hoford
454abb7d134c02ac60091108c491dafb00877093170John Hoford                if (mPathMeasure == null) {
455abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure = new PathMeasure();
456abb7d134c02ac60091108c491dafb00877093170John Hoford                }
457abb7d134c02ac60091108c491dafb00877093170John Hoford                mPathMeasure.setPath(mPath, false);
458abb7d134c02ac60091108c491dafb00877093170John Hoford
459abb7d134c02ac60091108c491dafb00877093170John Hoford                float len = mPathMeasure.getLength();
460abb7d134c02ac60091108c491dafb00877093170John Hoford                start = start * len;
461abb7d134c02ac60091108c491dafb00877093170John Hoford                end = end * len;
462abb7d134c02ac60091108c491dafb00877093170John Hoford                path.reset();
463abb7d134c02ac60091108c491dafb00877093170John Hoford                if (start > end) {
464abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, len, path, true);
465abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(0f, end, path, true);
466abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
467abb7d134c02ac60091108c491dafb00877093170John Hoford                    mPathMeasure.getSegment(start, end, path, true);
468abb7d134c02ac60091108c491dafb00877093170John Hoford                }
469abb7d134c02ac60091108c491dafb00877093170John Hoford                path.rLineTo(0, 0); // fix bug in measure
470abb7d134c02ac60091108c491dafb00877093170John Hoford            }
471abb7d134c02ac60091108c491dafb00877093170John Hoford
472abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.reset();
473abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.reset();
474abb7d134c02ac60091108c491dafb00877093170John Hoford
475abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
476abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
477abb7d134c02ac60091108c491dafb00877093170John Hoford            mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
478abb7d134c02ac60091108c491dafb00877093170John Hoford
479abb7d134c02ac60091108c491dafb00877093170John Hoford            mRenderPath.addPath(path, mMatrix);
480abb7d134c02ac60091108c491dafb00877093170John Hoford
481abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mClip) {
482abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
483abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
485abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mFillColor != 0) {
4864b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mFillPaint == null) {
4874b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint = new Paint();
4884b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setStyle(Paint.Style.FILL);
4894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mFillPaint.setAntiAlias(true);
4904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
4914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
492abb7d134c02ac60091108c491dafb00877093170John Hoford                mFillPaint.setColor(vPath.mFillColor);
493abb7d134c02ac60091108c491dafb00877093170John Hoford                canvas.drawPath(mRenderPath, mFillPaint);
494abb7d134c02ac60091108c491dafb00877093170John Hoford            }
4959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
496abb7d134c02ac60091108c491dafb00877093170John Hoford            if (vPath.mStrokeColor != 0) {
4974b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                if (mStrokePaint == null) {
4984b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint = new Paint();
4994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setStyle(Paint.Style.STROKE);
5004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    mStrokePaint.setAntiAlias(true);
5014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                }
5024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                final Paint strokePaint = mStrokePaint;
5047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineJoin != null) {
5054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
506abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                if (vPath.mStrokeLineCap != null) {
5094b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                    strokePaint.setStrokeCap(vPath.mStrokeLineCap);
510abb7d134c02ac60091108c491dafb00877093170John Hoford                }
5114b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
5124b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
5134b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setColor(vPath.mStrokeColor);
5144b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
5154b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette                canvas.drawPath(mRenderPath, strokePaint);
516abb7d134c02ac60091108c491dafb00877093170John Hoford            }
517abb7d134c02ac60091108c491dafb00877093170John Hoford        }
518abb7d134c02ac60091108c491dafb00877093170John Hoford
519abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
52046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui         * Build the "current" path based on the current group
521abb7d134c02ac60091108c491dafb00877093170John Hoford         * TODO: improve memory use & performance or move to C++
522abb7d134c02ac60091108c491dafb00877093170John Hoford         */
523abb7d134c02ac60091108c491dafb00877093170John Hoford        public void parseFinish() {
52446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui            final Collection<VPath> paths = mCurrentGroup.getPaths();
525abb7d134c02ac60091108c491dafb00877093170John Hoford            mCurrentPaths = paths.toArray(new VPath[paths.size()]);
526abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mCurrentPaths.length; i++) {
527abb7d134c02ac60091108c491dafb00877093170John Hoford                mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
528abb7d134c02ac60091108c491dafb00877093170John Hoford            }
529abb7d134c02ac60091108c491dafb00877093170John Hoford        }
530abb7d134c02ac60091108c491dafb00877093170John Hoford
531abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseViewport(Resources r, AttributeSet attrs)
532abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException {
5334b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
534abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0);
535abb7d134c02ac60091108c491dafb00877093170John Hoford            mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0);
536abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mViewportWidth == 0 || mViewportHeight == 0) {
537abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
538abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<viewport> tag requires viewportWidth & viewportHeight to be set");
539abb7d134c02ac60091108c491dafb00877093170John Hoford            }
540abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
541abb7d134c02ac60091108c491dafb00877093170John Hoford        }
542abb7d134c02ac60091108c491dafb00877093170John Hoford
543abb7d134c02ac60091108c491dafb00877093170John Hoford        private void parseSize(Resources r, AttributeSet attrs)
544abb7d134c02ac60091108c491dafb00877093170John Hoford                throws XmlPullParserException  {
5454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize);
546abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0);
547abb7d134c02ac60091108c491dafb00877093170John Hoford            mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0);
548abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mBaseWidth == 0 || mBaseHeight == 0) {
549abb7d134c02ac60091108c491dafb00877093170John Hoford                throw new XmlPullParserException(a.getPositionDescription()+
550abb7d134c02ac60091108c491dafb00877093170John Hoford                        "<size> tag requires width & height to be set");
551abb7d134c02ac60091108c491dafb00877093170John Hoford            }
552abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
553abb7d134c02ac60091108c491dafb00877093170John Hoford        }
5544b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette
555abb7d134c02ac60091108c491dafb00877093170John Hoford    }
556abb7d134c02ac60091108c491dafb00877093170John Hoford
557abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VGroup {
5589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
5599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
560abb7d134c02ac60091108c491dafb00877093170John Hoford
561abb7d134c02ac60091108c491dafb00877093170John Hoford        public void add(VPath path) {
562abb7d134c02ac60091108c491dafb00877093170John Hoford            String id = path.getID();
563abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGPathMap.put(id, path);
564abb7d134c02ac60091108c491dafb00877093170John Hoford            mVGList.add(path);
565abb7d134c02ac60091108c491dafb00877093170John Hoford         }
566abb7d134c02ac60091108c491dafb00877093170John Hoford
567abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
568abb7d134c02ac60091108c491dafb00877093170John Hoford         * Must return in order of adding
569abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return ordered list of paths
570abb7d134c02ac60091108c491dafb00877093170John Hoford         */
571abb7d134c02ac60091108c491dafb00877093170John Hoford        public Collection<VPath> getPaths() {
572abb7d134c02ac60091108c491dafb00877093170John Hoford            return mVGList;
573abb7d134c02ac60091108c491dafb00877093170John Hoford        }
574abb7d134c02ac60091108c491dafb00877093170John Hoford
575abb7d134c02ac60091108c491dafb00877093170John Hoford    }
576abb7d134c02ac60091108c491dafb00877093170John Hoford
577abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VPath {
578abb7d134c02ac60091108c491dafb00877093170John Hoford        private static final int MAX_STATES = 10;
5799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
5809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private int[] mThemeAttrs;
5819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
582abb7d134c02ac60091108c491dafb00877093170John Hoford        int mStrokeColor = 0;
583abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeWidth = 0;
584abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeOpacity = Float.NaN;
5859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
586abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillColor = 0;
587abb7d134c02ac60091108c491dafb00877093170John Hoford        int mFillRule;
588abb7d134c02ac60091108c491dafb00877093170John Hoford        float mFillOpacity = Float.NaN;
5899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
590abb7d134c02ac60091108c491dafb00877093170John Hoford        float mRotate = 0;
591abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotX = 0;
592abb7d134c02ac60091108c491dafb00877093170John Hoford        float mPivotY = 0;
5939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
594abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathStart = 0;
595abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathEnd = 1;
596abb7d134c02ac60091108c491dafb00877093170John Hoford        float mTrimPathOffset = 0;
5979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
598abb7d134c02ac60091108c491dafb00877093170John Hoford        boolean mClip = false;
5994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
6004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
601abb7d134c02ac60091108c491dafb00877093170John Hoford        float mStrokeMiterlimit = 4;
6029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private VNode[] mNode = null;
6049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private String mId;
605abb7d134c02ac60091108c491dafb00877093170John Hoford        private int[] mCheckState = new int[MAX_STATES];
606abb7d134c02ac60091108c491dafb00877093170John Hoford        private boolean[] mCheckValue = new boolean[MAX_STATES];
607abb7d134c02ac60091108c491dafb00877093170John Hoford        private int mNumberOfStates = 0;
608abb7d134c02ac60091108c491dafb00877093170John Hoford
6099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath() {
6109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            // Empty constructor.
6119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public VPath(VPath p) {
6149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            copyFrom(p);
6159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
6169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
617abb7d134c02ac60091108c491dafb00877093170John Hoford        public void toPath(Path path) {
618abb7d134c02ac60091108c491dafb00877093170John Hoford            path.reset();
619abb7d134c02ac60091108c491dafb00877093170John Hoford            if (mNode != null) {
620abb7d134c02ac60091108c491dafb00877093170John Hoford                VNode.createPath(mNode, path);
621abb7d134c02ac60091108c491dafb00877093170John Hoford            }
622abb7d134c02ac60091108c491dafb00877093170John Hoford        }
623abb7d134c02ac60091108c491dafb00877093170John Hoford
6247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        public String getID() {
625abb7d134c02ac60091108c491dafb00877093170John Hoford            return mId;
626abb7d134c02ac60091108c491dafb00877093170John Hoford        }
627abb7d134c02ac60091108c491dafb00877093170John Hoford
6287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
6297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_BUTT:
6317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.BUTT;
6327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_ROUND:
6337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.ROUND;
6347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINECAP_SQUARE:
6357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Cap.SQUARE;
6367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
6427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            switch (id) {
6437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_MITER:
6447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.MITER;
6457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_ROUND:
6467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.ROUND;
6477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                case LINEJOIN_BEVEL:
6487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return Paint.Join.BEVEL;
6497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                default:
6507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    return defValue;
6517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette        }
6537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
6559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
6569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final int[] themeAttrs = a.extractThemeAttrs();
6579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            mThemeAttrs = themeAttrs;
6589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // NOTE: The set of attributes loaded here MUST match the
6607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            // set of attributes loaded in applyTheme.
6617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) {
6627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
6637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
6667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
6677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
6707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
6717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
672abb7d134c02ac60091108c491dafb00877093170John Hoford
6739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
6747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) {
6787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
679abb7d134c02ac60091108c491dafb00877093170John Hoford            }
6809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
6827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
6837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
687abb7d134c02ac60091108c491dafb00877093170John Hoford            }
6889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
6907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
6917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
6957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineCap = getStrokeLineCap(
6967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
6997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) {
7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeLineJoin = getStrokeLineJoin(
7027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
703abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) {
7077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeMiterlimit = a.getFloat(
7087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) {
7129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
713abb7d134c02ac60091108c491dafb00877093170John Hoford            }
7149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (themeAttrs == null
7169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) {
7179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeOpacity = a.getFloat(
7187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
7199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) {
7227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
7237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) {
7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
7277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) {
7317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathOffset = a.getFloat(
7327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
7337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (themeAttrs == null
7367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) {
7377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mTrimPathStart = a.getFloat(
7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                        R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
7397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            }
7407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
7429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
743abb7d134c02ac60091108c491dafb00877093170John Hoford            a.recycle();
744abb7d134c02ac60091108c491dafb00877093170John Hoford        }
745abb7d134c02ac60091108c491dafb00877093170John Hoford
7469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public boolean canApplyTheme() {
7479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            return mThemeAttrs != null;
7489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        public void applyTheme(Theme t) {
7519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (mThemeAttrs == null) {
7529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                return;
7539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            final TypedArray a = t.resolveAttributes(
7569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
7579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
7599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
7617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mId = a.getString(R.styleable.VectorDrawablePath_name);
7629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
7657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
7669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
7679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
7697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
7707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
7727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
7737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
7747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = getStrokeLineCap(a.getInt(
7767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
7777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
7787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
7797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeMiterlimit = a.getFloat(
7807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
7817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor);
7827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeOpacity = a.getFloat(
7837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity);
7847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
7857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette
7867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
7877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathOffset = a.getFloat(
7887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
7897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mTrimPathStart = a.getFloat(
7907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
7919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            updateColorAlphas();
7939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
7949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
7959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        private void updateColorAlphas() {
7969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mFillOpacity)) {
7979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor &= 0x00FFFFFF;
7989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
7999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
8019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            if (!Float.isNaN(mStrokeOpacity)) {
8029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor &= 0x00FFFFFF;
8039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette                mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
8049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette            }
8059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette        }
8069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
807abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int nextStart(String s, int end) {
808abb7d134c02ac60091108c491dafb00877093170John Hoford            char c;
809abb7d134c02ac60091108c491dafb00877093170John Hoford
810abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < s.length()) {
811abb7d134c02ac60091108c491dafb00877093170John Hoford                c = s.charAt(end);
812abb7d134c02ac60091108c491dafb00877093170John Hoford                if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
813abb7d134c02ac60091108c491dafb00877093170John Hoford                    return end;
814abb7d134c02ac60091108c491dafb00877093170John Hoford                }
815abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
816abb7d134c02ac60091108c491dafb00877093170John Hoford            }
817abb7d134c02ac60091108c491dafb00877093170John Hoford            return end;
818abb7d134c02ac60091108c491dafb00877093170John Hoford        }
819abb7d134c02ac60091108c491dafb00877093170John Hoford
820abb7d134c02ac60091108c491dafb00877093170John Hoford        private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
821abb7d134c02ac60091108c491dafb00877093170John Hoford            list.add(new VectorDrawable.VNode(cmd, val));
822abb7d134c02ac60091108c491dafb00877093170John Hoford        }
823abb7d134c02ac60091108c491dafb00877093170John Hoford
824abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
825abb7d134c02ac60091108c491dafb00877093170John Hoford         * parse the floats in the string
826abb7d134c02ac60091108c491dafb00877093170John Hoford         * this is an optimized version of
827abb7d134c02ac60091108c491dafb00877093170John Hoford         * parseFloat(s.split(",|\\s"));
828abb7d134c02ac60091108c491dafb00877093170John Hoford         *
829abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string containing a command and list of floats
830abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return array of floats
831abb7d134c02ac60091108c491dafb00877093170John Hoford         */
832abb7d134c02ac60091108c491dafb00877093170John Hoford        private static float[] getFloats(String s) {
833abb7d134c02ac60091108c491dafb00877093170John Hoford            if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
834abb7d134c02ac60091108c491dafb00877093170John Hoford                return new float[0];
835abb7d134c02ac60091108c491dafb00877093170John Hoford            }
836abb7d134c02ac60091108c491dafb00877093170John Hoford            try {
837abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] tmp = new float[s.length()];
838abb7d134c02ac60091108c491dafb00877093170John Hoford                int count = 0;
839abb7d134c02ac60091108c491dafb00877093170John Hoford                int pos = 1, end;
840abb7d134c02ac60091108c491dafb00877093170John Hoford                while ((end = extract(s, pos)) >= 0) {
841abb7d134c02ac60091108c491dafb00877093170John Hoford                    if (pos < end) {
842abb7d134c02ac60091108c491dafb00877093170John Hoford                        tmp[count++] = Float.parseFloat(s.substring(pos, end));
843abb7d134c02ac60091108c491dafb00877093170John Hoford                    }
844abb7d134c02ac60091108c491dafb00877093170John Hoford                    pos = end + 1;
845abb7d134c02ac60091108c491dafb00877093170John Hoford                }
846abb7d134c02ac60091108c491dafb00877093170John Hoford                // handle the final float if there is one
847abb7d134c02ac60091108c491dafb00877093170John Hoford                if (pos < s.length()) {
848abb7d134c02ac60091108c491dafb00877093170John Hoford                    tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
849abb7d134c02ac60091108c491dafb00877093170John Hoford                }
850abb7d134c02ac60091108c491dafb00877093170John Hoford                return Arrays.copyOf(tmp, count);
851abb7d134c02ac60091108c491dafb00877093170John Hoford            } catch (NumberFormatException e){
852abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.e(LOGTAG,"error in parsing \""+s+"\"");
853abb7d134c02ac60091108c491dafb00877093170John Hoford                throw e;
854abb7d134c02ac60091108c491dafb00877093170John Hoford            }
855abb7d134c02ac60091108c491dafb00877093170John Hoford        }
856abb7d134c02ac60091108c491dafb00877093170John Hoford
857abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
858abb7d134c02ac60091108c491dafb00877093170John Hoford         * calculate the position of the next comma or space
859abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param s the string to search
860abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start the position to start searching
861abb7d134c02ac60091108c491dafb00877093170John Hoford         * @return the position of the next comma or space or -1 if none found
862abb7d134c02ac60091108c491dafb00877093170John Hoford         */
863abb7d134c02ac60091108c491dafb00877093170John Hoford        private static int extract(String s, int start) {
864abb7d134c02ac60091108c491dafb00877093170John Hoford            int space = s.indexOf(' ', start);
865abb7d134c02ac60091108c491dafb00877093170John Hoford            int comma = s.indexOf(',', start);
866abb7d134c02ac60091108c491dafb00877093170John Hoford            if (space == -1) {
867abb7d134c02ac60091108c491dafb00877093170John Hoford                return comma;
868abb7d134c02ac60091108c491dafb00877093170John Hoford            }
869abb7d134c02ac60091108c491dafb00877093170John Hoford            if (comma == -1) {
870abb7d134c02ac60091108c491dafb00877093170John Hoford                return space;
871abb7d134c02ac60091108c491dafb00877093170John Hoford            }
872abb7d134c02ac60091108c491dafb00877093170John Hoford            return (comma > space) ? space : comma;
873abb7d134c02ac60091108c491dafb00877093170John Hoford        }
874abb7d134c02ac60091108c491dafb00877093170John Hoford
875abb7d134c02ac60091108c491dafb00877093170John Hoford        private VectorDrawable.VNode[] parsePath(String value) {
876abb7d134c02ac60091108c491dafb00877093170John Hoford            int start = 0;
877abb7d134c02ac60091108c491dafb00877093170John Hoford            int end = 1;
878abb7d134c02ac60091108c491dafb00877093170John Hoford
879abb7d134c02ac60091108c491dafb00877093170John Hoford            ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
880abb7d134c02ac60091108c491dafb00877093170John Hoford            while (end < value.length()) {
881abb7d134c02ac60091108c491dafb00877093170John Hoford                end = nextStart(value, end);
882abb7d134c02ac60091108c491dafb00877093170John Hoford                String s = value.substring(start, end);
883abb7d134c02ac60091108c491dafb00877093170John Hoford                float[] val = getFloats(s);
884abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, s.charAt(0), val);
885abb7d134c02ac60091108c491dafb00877093170John Hoford
886abb7d134c02ac60091108c491dafb00877093170John Hoford                start = end;
887abb7d134c02ac60091108c491dafb00877093170John Hoford                end++;
888abb7d134c02ac60091108c491dafb00877093170John Hoford            }
889abb7d134c02ac60091108c491dafb00877093170John Hoford            if ((end - start) == 1 && start < value.length()) {
890abb7d134c02ac60091108c491dafb00877093170John Hoford
891abb7d134c02ac60091108c491dafb00877093170John Hoford                addNode(list, value.charAt(start), new float[0]);
892abb7d134c02ac60091108c491dafb00877093170John Hoford            }
893abb7d134c02ac60091108c491dafb00877093170John Hoford            return list.toArray(new VectorDrawable.VNode[list.size()]);
894abb7d134c02ac60091108c491dafb00877093170John Hoford        }
895abb7d134c02ac60091108c491dafb00877093170John Hoford
896abb7d134c02ac60091108c491dafb00877093170John Hoford        public void copyFrom(VPath p1) {
897abb7d134c02ac60091108c491dafb00877093170John Hoford            mNode = new VNode[p1.mNode.length];
898abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNode.length; i++) {
899abb7d134c02ac60091108c491dafb00877093170John Hoford                mNode[i] = new VNode(p1.mNode[i]);
900abb7d134c02ac60091108c491dafb00877093170John Hoford            }
901abb7d134c02ac60091108c491dafb00877093170John Hoford            mId = p1.mId;
902abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeColor = p1.mStrokeColor;
903abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillColor = p1.mFillColor;
904abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeWidth = p1.mStrokeWidth;
905abb7d134c02ac60091108c491dafb00877093170John Hoford            mRotate = p1.mRotate;
906abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotX = p1.mPivotX;
907abb7d134c02ac60091108c491dafb00877093170John Hoford            mPivotY = p1.mPivotY;
908abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathStart = p1.mTrimPathStart;
909abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathEnd = p1.mTrimPathEnd;
910abb7d134c02ac60091108c491dafb00877093170John Hoford            mTrimPathOffset = p1.mTrimPathOffset;
9117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineCap = p1.mStrokeLineCap;
9127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette            mStrokeLineJoin = p1.mStrokeLineJoin;
913abb7d134c02ac60091108c491dafb00877093170John Hoford            mStrokeMiterlimit = p1.mStrokeMiterlimit;
914abb7d134c02ac60091108c491dafb00877093170John Hoford            mNumberOfStates = p1.mNumberOfStates;
915abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < mNumberOfStates; i++) {
916abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckState[i] = p1.mCheckState[i];
917abb7d134c02ac60091108c491dafb00877093170John Hoford                mCheckValue[i] = p1.mCheckValue[i];
918abb7d134c02ac60091108c491dafb00877093170John Hoford            }
919abb7d134c02ac60091108c491dafb00877093170John Hoford
920abb7d134c02ac60091108c491dafb00877093170John Hoford            mFillRule = p1.mFillRule;
921abb7d134c02ac60091108c491dafb00877093170John Hoford        }
922abb7d134c02ac60091108c491dafb00877093170John Hoford    }
923abb7d134c02ac60091108c491dafb00877093170John Hoford
924abb7d134c02ac60091108c491dafb00877093170John Hoford    private static class VNode {
9255c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private char mType;
9265c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette        private float[] mParams;
9279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette
928abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(char type, float[] params) {
9295c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = type;
9305c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = params;
931abb7d134c02ac60091108c491dafb00877093170John Hoford        }
932abb7d134c02ac60091108c491dafb00877093170John Hoford
933abb7d134c02ac60091108c491dafb00877093170John Hoford        public VNode(VNode n) {
9345c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mType = n.mType;
9355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
936abb7d134c02ac60091108c491dafb00877093170John Hoford        }
937abb7d134c02ac60091108c491dafb00877093170John Hoford
938abb7d134c02ac60091108c491dafb00877093170John Hoford        public static void createPath(VNode[] node, Path path) {
9395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette            float[] current = new float[4];
94033ed52eff4b41f88858874e1af7723277a041b56ztenghui            char previousCommand = 'm';
941abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < node.length; i++) {
94233ed52eff4b41f88858874e1af7723277a041b56ztenghui                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
94333ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCommand = node[i].mType;
944abb7d134c02ac60091108c491dafb00877093170John Hoford            }
945abb7d134c02ac60091108c491dafb00877093170John Hoford        }
946abb7d134c02ac60091108c491dafb00877093170John Hoford
94733ed52eff4b41f88858874e1af7723277a041b56ztenghui        private static void addCommand(Path path, float[] current,
94833ed52eff4b41f88858874e1af7723277a041b56ztenghui                char previousCmd, char cmd, float[] val) {
949abb7d134c02ac60091108c491dafb00877093170John Hoford
950abb7d134c02ac60091108c491dafb00877093170John Hoford            int incr = 2;
951abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentX = current[0];
952abb7d134c02ac60091108c491dafb00877093170John Hoford            float currentY = current[1];
953abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointX = current[2];
954abb7d134c02ac60091108c491dafb00877093170John Hoford            float ctrlPointY = current[3];
95533ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointX;
95633ed52eff4b41f88858874e1af7723277a041b56ztenghui            float reflectiveCtrlPointY;
957abb7d134c02ac60091108c491dafb00877093170John Hoford
958abb7d134c02ac60091108c491dafb00877093170John Hoford            switch (cmd) {
959abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'z':
960abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Z':
961abb7d134c02ac60091108c491dafb00877093170John Hoford                    path.close();
962abb7d134c02ac60091108c491dafb00877093170John Hoford                    return;
963abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'm':
964abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'M':
965abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'l':
966abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'L':
967abb7d134c02ac60091108c491dafb00877093170John Hoford                case 't':
968abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'T':
969abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 2;
970abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
971abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'h':
972abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'H':
973abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'v':
974abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'V':
975abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 1;
976abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
977abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'c':
978abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'C':
979abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 6;
980abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
981abb7d134c02ac60091108c491dafb00877093170John Hoford                case 's':
982abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'S':
983abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'q':
984abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'Q':
985abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 4;
986abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
987abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'a':
988abb7d134c02ac60091108c491dafb00877093170John Hoford                case 'A':
989abb7d134c02ac60091108c491dafb00877093170John Hoford                    incr = 7;
990abb7d134c02ac60091108c491dafb00877093170John Hoford                    break;
991abb7d134c02ac60091108c491dafb00877093170John Hoford            }
992abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int k = 0; k < val.length; k += incr) {
993abb7d134c02ac60091108c491dafb00877093170John Hoford                switch (cmd) {
994abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'm': // moveto - Start a new sub-path (relative)
995abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rMoveTo(val[k + 0], val[k + 1]);
996abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
997abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
998abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
999abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'M': // moveto - Start a new sub-path
1000abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.moveTo(val[k + 0], val[k + 1]);
1001abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1002abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1003abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1004abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'l': // lineto - Draw a line from the current point (relative)
1005abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], val[k + 1]);
1006abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1007abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1008abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1009abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'L': // lineto - Draw a line from the current point
1010abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], val[k + 1]);
1011abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1012abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 1];
1013abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1014abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'z': // closepath - Close the current subpath
1015abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Z': // closepath - Close the current subpath
1016abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.close();
1017abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1018abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
1019abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(val[k + 0], 0);
1020abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1021abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1022abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'H': // horizontal lineto - Draws a horizontal line
1023abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(val[k + 0], currentY);
1024abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
1025abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1026abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
1027abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rLineTo(0, val[k + 0]);
1028abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 0];
1029abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1030abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'V': // vertical lineto - Draws a vertical line from the current point
1031abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.lineTo(currentX, val[k + 0]);
1032abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 0];
1033abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1034abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
103533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
103633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1037abb7d134c02ac60091108c491dafb00877093170John Hoford
1038abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 2];
1039abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 3];
1040abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 4];
1041abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 5];
1042abb7d134c02ac60091108c491dafb00877093170John Hoford
1043abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1044abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'C': // curveto - Draws a cubic Bézier curve
104533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
104633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 4], val[k + 5]);
1047abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 4];
1048abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 5];
1049abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 2];
1050abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 3];
1051abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1052abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
105333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
105433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
105533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
105633ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
105733ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
105833ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
105933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
106033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1061abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1],
1062abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2], val[k + 3]);
1063abb7d134c02ac60091108c491dafb00877093170John Hoford
1064abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX + val[k + 0];
1065abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY + val[k + 1];
1066abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1067abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1068abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1069abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
107033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
107133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
107233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'c' || previousCmd == 's'
107333ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'C' || previousCmd == 'S') {
107433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
107533ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
107633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
107733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
107833ed52eff4b41f88858874e1af7723277a041b56ztenghui                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1079abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1080abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
108133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
108233ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1083abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1084abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'q': // Draws a quadratic Bézier (relative)
1085abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
108633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = currentX + val[k + 0];
108733ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = currentY + val[k + 1];
1088abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 2];
1089abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 3];
1090abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1091abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'Q': // Draws a quadratic Bézier
1092abb7d134c02ac60091108c491dafb00877093170John Hoford                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
1093abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = val[k + 0];
1094abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = val[k + 1];
109533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentX = val[k + 2];
109633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 3];
1097abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1098abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
109933ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = 0;
110033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = 0;
110133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
110233ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
110333ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = currentX - ctrlPointX;
110433ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = currentY - ctrlPointY;
110533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
110633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1107abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
1108175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointX = currentX + reflectiveCtrlPointX;
1109175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui                        ctrlPointY = currentY + reflectiveCtrlPointY;
1110abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 0];
1111abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 1];
1112abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1113abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
111433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointX = currentX;
111533ed52eff4b41f88858874e1af7723277a041b56ztenghui                        reflectiveCtrlPointY = currentY;
111633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        if (previousCmd == 'q' || previousCmd == 't'
111733ed52eff4b41f88858874e1af7723277a041b56ztenghui                                || previousCmd == 'Q' || previousCmd == 'T') {
111833ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
111933ed52eff4b41f88858874e1af7723277a041b56ztenghui                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
112033ed52eff4b41f88858874e1af7723277a041b56ztenghui                        }
112133ed52eff4b41f88858874e1af7723277a041b56ztenghui                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
1122abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0], val[k + 1]);
112333ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointX = reflectiveCtrlPointX;
112433ed52eff4b41f88858874e1af7723277a041b56ztenghui                        ctrlPointY = reflectiveCtrlPointY;
1125abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 0];
112633ed52eff4b41f88858874e1af7723277a041b56ztenghui                        currentY = val[k + 1];
1127abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1128abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'a': // Draws an elliptical arc
1129abb7d134c02ac60091108c491dafb00877093170John Hoford                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
1130abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1131abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1132abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1133abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5] + currentX,
1134abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6] + currentY,
1135abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1136abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1137abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1138abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1139abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1140abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX += val[k + 5];
1141abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY += val[k + 6];
1142abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1143abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1144abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1145abb7d134c02ac60091108c491dafb00877093170John Hoford                    case 'A': // Draws an elliptical arc
1146abb7d134c02ac60091108c491dafb00877093170John Hoford                        drawArc(path,
1147abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentX,
1148abb7d134c02ac60091108c491dafb00877093170John Hoford                                currentY,
1149abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 5],
1150abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 6],
1151abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 0],
1152abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 1],
1153abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 2],
1154abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 3] != 0,
1155abb7d134c02ac60091108c491dafb00877093170John Hoford                                val[k + 4] != 0);
1156abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentX = val[k + 5];
1157abb7d134c02ac60091108c491dafb00877093170John Hoford                        currentY = val[k + 6];
1158abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointX = currentX;
1159abb7d134c02ac60091108c491dafb00877093170John Hoford                        ctrlPointY = currentY;
1160abb7d134c02ac60091108c491dafb00877093170John Hoford                        break;
1161abb7d134c02ac60091108c491dafb00877093170John Hoford                }
116233ed52eff4b41f88858874e1af7723277a041b56ztenghui                previousCmd = cmd;
1163abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1164abb7d134c02ac60091108c491dafb00877093170John Hoford            current[0] = currentX;
1165abb7d134c02ac60091108c491dafb00877093170John Hoford            current[1] = currentY;
1166abb7d134c02ac60091108c491dafb00877093170John Hoford            current[2] = ctrlPointX;
1167abb7d134c02ac60091108c491dafb00877093170John Hoford            current[3] = ctrlPointY;
1168abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1169abb7d134c02ac60091108c491dafb00877093170John Hoford
1170abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void drawArc(Path p,
1171abb7d134c02ac60091108c491dafb00877093170John Hoford                float x0,
1172abb7d134c02ac60091108c491dafb00877093170John Hoford                float y0,
1173abb7d134c02ac60091108c491dafb00877093170John Hoford                float x1,
1174abb7d134c02ac60091108c491dafb00877093170John Hoford                float y1,
1175abb7d134c02ac60091108c491dafb00877093170John Hoford                float a,
1176abb7d134c02ac60091108c491dafb00877093170John Hoford                float b,
1177abb7d134c02ac60091108c491dafb00877093170John Hoford                float theta,
1178abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isMoreThanHalf,
1179abb7d134c02ac60091108c491dafb00877093170John Hoford                boolean isPositiveArc) {
1180abb7d134c02ac60091108c491dafb00877093170John Hoford
1181abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Convert rotation angle from degrees to radians */
1182abb7d134c02ac60091108c491dafb00877093170John Hoford            double thetaD = Math.toRadians(theta);
1183abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Pre-compute rotation matrix entries */
1184abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(thetaD);
1185abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(thetaD);
1186abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Transform (x0, y0) and (x1, y1) into unit space */
1187abb7d134c02ac60091108c491dafb00877093170John Hoford            /* using (inverse) rotation, followed by (inverse) scale */
1188abb7d134c02ac60091108c491dafb00877093170John Hoford            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
1189abb7d134c02ac60091108c491dafb00877093170John Hoford            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
1190abb7d134c02ac60091108c491dafb00877093170John Hoford            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
1191abb7d134c02ac60091108c491dafb00877093170John Hoford            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
1192abb7d134c02ac60091108c491dafb00877093170John Hoford
1193abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Compute differences and averages */
1194abb7d134c02ac60091108c491dafb00877093170John Hoford            double dx = x0p - x1p;
1195abb7d134c02ac60091108c491dafb00877093170John Hoford            double dy = y0p - y1p;
1196abb7d134c02ac60091108c491dafb00877093170John Hoford            double xm = (x0p + x1p) / 2;
1197abb7d134c02ac60091108c491dafb00877093170John Hoford            double ym = (y0p + y1p) / 2;
1198abb7d134c02ac60091108c491dafb00877093170John Hoford            /* Solve for intersecting unit circles */
1199abb7d134c02ac60091108c491dafb00877093170John Hoford            double dsq = dx * dx + dy * dy;
1200abb7d134c02ac60091108c491dafb00877093170John Hoford            if (dsq == 0.0) {
1201abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, " Points are coincident");
1202abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are coincident */
1203abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1204abb7d134c02ac60091108c491dafb00877093170John Hoford            double disc = 1.0 / dsq - 1.0 / 4.0;
1205abb7d134c02ac60091108c491dafb00877093170John Hoford            if (disc < 0.0) {
1206abb7d134c02ac60091108c491dafb00877093170John Hoford                Log.w(LOGTAG, "Points are too far apart " + dsq);
1207abb7d134c02ac60091108c491dafb00877093170John Hoford                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
1208abb7d134c02ac60091108c491dafb00877093170John Hoford                drawArc(p, x0, y0, x1, y1, a * adjust,
1209abb7d134c02ac60091108c491dafb00877093170John Hoford                        b * adjust, theta, isMoreThanHalf, isPositiveArc);
1210abb7d134c02ac60091108c491dafb00877093170John Hoford                return; /* Points are too far apart */
1211abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1212abb7d134c02ac60091108c491dafb00877093170John Hoford            double s = Math.sqrt(disc);
1213abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdx = s * dx;
1214abb7d134c02ac60091108c491dafb00877093170John Hoford            double sdy = s * dy;
1215abb7d134c02ac60091108c491dafb00877093170John Hoford            double cx;
1216abb7d134c02ac60091108c491dafb00877093170John Hoford            double cy;
1217abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isMoreThanHalf == isPositiveArc) {
1218abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm - sdy;
1219abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym + sdx;
1220abb7d134c02ac60091108c491dafb00877093170John Hoford            } else {
1221abb7d134c02ac60091108c491dafb00877093170John Hoford                cx = xm + sdy;
1222abb7d134c02ac60091108c491dafb00877093170John Hoford                cy = ym - sdx;
1223abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1224abb7d134c02ac60091108c491dafb00877093170John Hoford
1225abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
1226abb7d134c02ac60091108c491dafb00877093170John Hoford
1227abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
1228abb7d134c02ac60091108c491dafb00877093170John Hoford
1229abb7d134c02ac60091108c491dafb00877093170John Hoford            double sweep = (eta1 - eta0);
1230abb7d134c02ac60091108c491dafb00877093170John Hoford            if (isPositiveArc != (sweep >= 0)) {
1231abb7d134c02ac60091108c491dafb00877093170John Hoford                if (sweep > 0) {
1232abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep -= 2 * Math.PI;
1233abb7d134c02ac60091108c491dafb00877093170John Hoford                } else {
1234abb7d134c02ac60091108c491dafb00877093170John Hoford                    sweep += 2 * Math.PI;
1235abb7d134c02ac60091108c491dafb00877093170John Hoford                }
1236abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1237abb7d134c02ac60091108c491dafb00877093170John Hoford
1238abb7d134c02ac60091108c491dafb00877093170John Hoford            cx *= a;
1239abb7d134c02ac60091108c491dafb00877093170John Hoford            cy *= b;
1240abb7d134c02ac60091108c491dafb00877093170John Hoford            double tcx = cx;
1241abb7d134c02ac60091108c491dafb00877093170John Hoford            cx = cx * cosTheta - cy * sinTheta;
1242abb7d134c02ac60091108c491dafb00877093170John Hoford            cy = tcx * sinTheta + cy * cosTheta;
1243abb7d134c02ac60091108c491dafb00877093170John Hoford
1244abb7d134c02ac60091108c491dafb00877093170John Hoford            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
1245abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1246abb7d134c02ac60091108c491dafb00877093170John Hoford
1247abb7d134c02ac60091108c491dafb00877093170John Hoford        /**
1248abb7d134c02ac60091108c491dafb00877093170John Hoford         * Converts an arc to cubic Bezier segments and records them in p.
1249abb7d134c02ac60091108c491dafb00877093170John Hoford         *
1250abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param p The target for the cubic Bezier segments
1251abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cx The x coordinate center of the ellipse
1252abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param cy The y coordinate center of the ellipse
1253abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param a The radius of the ellipse in the horizontal direction
1254abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param b The radius of the ellipse in the vertical direction
1255abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1x E(eta1) x coordinate of the starting point of the arc
1256abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param e1y E(eta2) y coordinate of the starting point of the arc
1257abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
1258abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param start The start angle of the arc on the ellipse
1259abb7d134c02ac60091108c491dafb00877093170John Hoford         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
1260abb7d134c02ac60091108c491dafb00877093170John Hoford         */
1261abb7d134c02ac60091108c491dafb00877093170John Hoford        private static void arcToBezier(Path p,
1262abb7d134c02ac60091108c491dafb00877093170John Hoford                double cx,
1263abb7d134c02ac60091108c491dafb00877093170John Hoford                double cy,
1264abb7d134c02ac60091108c491dafb00877093170John Hoford                double a,
1265abb7d134c02ac60091108c491dafb00877093170John Hoford                double b,
1266abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1x,
1267abb7d134c02ac60091108c491dafb00877093170John Hoford                double e1y,
1268abb7d134c02ac60091108c491dafb00877093170John Hoford                double theta,
1269abb7d134c02ac60091108c491dafb00877093170John Hoford                double start,
1270abb7d134c02ac60091108c491dafb00877093170John Hoford                double sweep) {
1271abb7d134c02ac60091108c491dafb00877093170John Hoford            // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
1272abb7d134c02ac60091108c491dafb00877093170John Hoford            // and http://www.spaceroots.org/documents/ellipse/node22.html
1273abb7d134c02ac60091108c491dafb00877093170John Hoford
1274abb7d134c02ac60091108c491dafb00877093170John Hoford            // Maximum of 45 degrees per cubic Bezier segment
1275abb7d134c02ac60091108c491dafb00877093170John Hoford            int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
1276abb7d134c02ac60091108c491dafb00877093170John Hoford
1277abb7d134c02ac60091108c491dafb00877093170John Hoford            double eta1 = start;
1278abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosTheta = Math.cos(theta);
1279abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinTheta = Math.sin(theta);
1280abb7d134c02ac60091108c491dafb00877093170John Hoford            double cosEta1 = Math.cos(eta1);
1281abb7d134c02ac60091108c491dafb00877093170John Hoford            double sinEta1 = Math.sin(eta1);
1282abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
1283abb7d134c02ac60091108c491dafb00877093170John Hoford            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
1284abb7d134c02ac60091108c491dafb00877093170John Hoford
1285abb7d134c02ac60091108c491dafb00877093170John Hoford            double anglePerSegment = sweep / numSegments;
1286abb7d134c02ac60091108c491dafb00877093170John Hoford            for (int i = 0; i < numSegments; i++) {
1287abb7d134c02ac60091108c491dafb00877093170John Hoford                double eta2 = eta1 + anglePerSegment;
1288abb7d134c02ac60091108c491dafb00877093170John Hoford                double sinEta2 = Math.sin(eta2);
1289abb7d134c02ac60091108c491dafb00877093170John Hoford                double cosEta2 = Math.cos(eta2);
1290abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
1291abb7d134c02ac60091108c491dafb00877093170John Hoford                double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
1292abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
1293abb7d134c02ac60091108c491dafb00877093170John Hoford                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
1294abb7d134c02ac60091108c491dafb00877093170John Hoford                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
1295abb7d134c02ac60091108c491dafb00877093170John Hoford                double alpha =
1296abb7d134c02ac60091108c491dafb00877093170John Hoford                        Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
1297abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1x = e1x + alpha * ep1x;
1298abb7d134c02ac60091108c491dafb00877093170John Hoford                double q1y = e1y + alpha * ep1y;
1299abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2x = e2x - alpha * ep2x;
1300abb7d134c02ac60091108c491dafb00877093170John Hoford                double q2y = e2y - alpha * ep2y;
1301abb7d134c02ac60091108c491dafb00877093170John Hoford
1302abb7d134c02ac60091108c491dafb00877093170John Hoford                p.cubicTo((float) q1x,
1303abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q1y,
1304abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2x,
1305abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) q2y,
1306abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2x,
1307abb7d134c02ac60091108c491dafb00877093170John Hoford                        (float) e2y);
1308abb7d134c02ac60091108c491dafb00877093170John Hoford                eta1 = eta2;
1309abb7d134c02ac60091108c491dafb00877093170John Hoford                e1x = e2x;
1310abb7d134c02ac60091108c491dafb00877093170John Hoford                e1y = e2y;
1311abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1x = ep2x;
1312abb7d134c02ac60091108c491dafb00877093170John Hoford                ep1y = ep2y;
1313abb7d134c02ac60091108c491dafb00877093170John Hoford            }
1314abb7d134c02ac60091108c491dafb00877093170John Hoford        }
1315abb7d134c02ac60091108c491dafb00877093170John Hoford
1316abb7d134c02ac60091108c491dafb00877093170John Hoford    }
1317abb7d134c02ac60091108c491dafb00877093170John Hoford}
1318