VectorDrawable.java revision 34c623cbf3677820c4170f24c5211f663dda91f7
1e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/*
2e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Copyright (C) 2014 The Android Open Source Project
3e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
4e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * in compliance with the License. You may obtain a copy of the License at
6e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
7e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * http://www.apache.org/licenses/LICENSE-2.0
8e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
9e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Unless required by applicable law or agreed to in writing, software distributed under the License
10e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * or implied. See the License for the specific language governing permissions and limitations under
12e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * the License.
13e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
14e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
15e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guypackage android.graphics.drawable;
16e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guyimport android.annotation.NonNull;
18e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.content.res.ColorStateList;
19e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.content.res.Resources;
20e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.content.res.Resources.Theme;
21e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.content.res.TypedArray;
22e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Bitmap;
23bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyimport android.graphics.Canvas;
24694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyimport android.graphics.Color;
255cbbce535744b89df5ecea95de21ee3733298260Romain Guyimport android.graphics.ColorFilter;
265cbbce535744b89df5ecea95de21ee3733298260Romain Guyimport android.graphics.Matrix;
27e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guyimport android.graphics.Paint;
2885bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guyimport android.graphics.Path;
295b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyimport android.graphics.PathMeasure;
305b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyimport android.graphics.PixelFormat;
3185bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guyimport android.graphics.PorterDuffColorFilter;
320fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guyimport android.graphics.Rect;
33a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guyimport android.graphics.Region;
34e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.PorterDuff.Mode;
35e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.util.ArrayMap;
369d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport android.util.AttributeSet;
379d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport android.util.LayoutDirection;
389d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport android.util.Log;
399d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport android.util.PathParser;
409d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport android.util.Xml;
419d5316e3f56d138504565ff311145ac01621dff4Romain Guy
42759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guyimport com.android.internal.R;
43759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
44759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guyimport org.xmlpull.v1.XmlPullParser;
45dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guyimport org.xmlpull.v1.XmlPullParserException;
46dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
47dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guyimport java.io.IOException;
489d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport java.util.ArrayList;
499d5316e3f56d138504565ff311145ac01621dff4Romain Guyimport java.util.Stack;
509d5316e3f56d138504565ff311145ac01621dff4Romain Guy
519d5316e3f56d138504565ff311145ac01621dff4Romain Guy/**
52889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * This lets you create a drawable based on an XML vector graphic. It can be
53889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * defined in an XML file with the <code>&lt;vector></code> element.
54889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <p/>
55889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * The vector drawable has the following elements:
56889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <p/>
57889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <dt><code>&lt;vector></code></dt>
58889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <dl>
59889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <dd>Used to defined a vector drawable
60889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <dl>
61026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy * <dt><code>android:name</code></dt>
62026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy * <dd>Defines the name of this vector drawable.</dd>
63026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy * <dt><code>android:width</code></dt>
64b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>Used to defined the intrinsic width of the drawable.
65b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * This support all the dimension units, normally specified with dp.</dd>
66b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:height</code></dt>
67b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>Used to defined the intrinsic height the drawable.
68b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * This support all the dimension units, normally specified with dp.</dd>
69b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:viewportWidth</code></dt>
70b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>Used to defined the width of the viewport space. Viewport is basically
71b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * the virtual canvas where the paths are drawn on.</dd>
72b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:viewportHeight</code></dt>
73b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>Used to defined the height of the viewport space. Viewport is basically
74b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * the virtual canvas where the paths are drawn on.</dd>
75b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:tint</code></dt>
76026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
77e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * <dt><code>android:tintMode</code></dt>
7887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
7987a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * <dt><code>android:autoMirrored</code></dt>
8087a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * <dd>Indicates if the drawable needs to be mirrored when its layout direction is
81f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy * RTL (right-to-left).</dd>
82b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:alpha</code></dt>
83b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>The opacity of this drawable.</dd>
84b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * </dl></dd>
85b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * </dl>
86b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy *
87b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dl>
88b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>&lt;group></code></dt>
89b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>Defines a group of paths or subgroups, plus transformation information.
90b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * The transformations are defined in the same coordinates as the viewport.
91b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * And the transformations are applied in the order of scale, rotate then translate.
92b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dl>
93b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:name</code></dt>
94f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy * <dd>Defines the name of the group.</dd>
95f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy * <dt><code>android:rotation</code></dt>
96889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * <dd>The degrees of rotation of the group.</dd>
97b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dt><code>android:pivotX</code></dt>
98b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * <dd>The X coordinate of the pivot for the scale and rotation of the group.
99b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy * This is defined in the viewport space.</dd>
100d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy * <dt><code>android:pivotY</code></dt>
101d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy * <dd>The Y coordinate of the pivot for the scale and rotation of the group.
102f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * This is defined in the viewport space.</dd>
103f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dt><code>android:scaleX</code></dt>
104f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dd>The amount of scale on the X Coordinate.</dd>
105f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dt><code>android:scaleY</code></dt>
106fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy * <dd>The amount of scale on the Y coordinate.</dd>
10706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy * <dt><code>android:translateX</code></dt>
108db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy * <dd>The amount of translation on the X coordinate.
1091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * This is defined in the viewport space.</dd>
110026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy * <dt><code>android:translateY</code></dt>
111ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * <dd>The amount of translation on the Y coordinate.
112ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * This is defined in the viewport space.</dd>
113ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy * </dl></dd>
114e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * </dl>
115e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
11685bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy * <dl>
11729d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy * <dt><code>&lt;path></code></dt>
11829d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy * <dd>Defines paths to be drawn.
119e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * <dl>
120e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * <dt><code>android:name</code></dt>
121f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dd>Defines the name of the path.</dd>
122f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dt><code>android:pathData</code></dt>
123f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dd>Defines path string. This is using exactly same format as "d" attribute
124f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * in the SVG's path data. This is defined in the viewport space.</dd>
12585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy * <dt><code>android:fillColor</code></dt>
12608ae317c21ec3086b5017672bba87420cc38a407Romain Guy * <dd>Defines the color to fill the path (none if not present).</dd>
127260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy * <dt><code>android:strokeColor</code></dt>
128bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * <dd>Defines the color to draw the path outline (none if not present).</dd>
129bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * <dt><code>android:strokeWidth</code></dt>
130bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * <dd>The width a path stroke.</dd>
131eb99356a0548684a501766e6a524529ab93304c8Romain Guy * <dt><code>android:strokeAlpha</code></dt>
132eb99356a0548684a501766e6a524529ab93304c8Romain Guy * <dd>The opacity of a path stroke.</dd>
133eb99356a0548684a501766e6a524529ab93304c8Romain Guy * <dt><code>android:fillAlpha</code></dt>
134746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy * <dd>The opacity to fill the path with.</dd>
135746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy * <dt><code>android:trimPathStart</code></dt>
136e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
137e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * <dt><code>android:trimPathEnd</code></dt>
1386b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
139fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy * <dt><code>android:trimPathOffset</code></dt>
140fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy * <dd>Shift trim region (allows showed region to include the start and end), in the range
1418aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy * from 0 to 1.</dd>
1428aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy * <dt><code>android:strokeLineCap</code></dt>
1438fb954263dd2f918ad339045cc6d82e346515599Romain Guy * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
144f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy * <dt><code>android:strokeLineJoin</code></dt>
145fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
146fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy * <dt><code>android:strokeMiterLimit</code></dt>
147d90f23e24a4d1768d5a7ed0e7072e67af6330a45Romain Guy * <dd>Sets the Miter limit for a stroked path.</dd>
148bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * </dl></dd>
1496b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * </dl>
150746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy *
1516b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * <dl>
1526b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * <dt><code>&lt;clip-path></code></dt>
1536b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * <dd>Defines path to be the current clip. Note that the clip path only apply to
154bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * the current group and its children.
1550d200833fdc53f9796698f97c18cefc4a1b82df2Chet Haase * <dl>
1560d200833fdc53f9796698f97c18cefc4a1b82df2Chet Haase * <dt><code>android:name</code></dt>
157b82da65cb1601be504241f36778395cd6cb9f87bRomain Guy * <dd>Defines the name of the clip path.</dd>
158bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * <dt><code>android:pathData</code></dt>
159bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy * <dd>Defines clip path string. This is using exactly same format as "d" attribute
160b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy * in the SVG's path data.</dd>
161b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy * </dl></dd>
162b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy * </dl>
163b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
164b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy * <pre>
165a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android";
166a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy *     android:height=&quot;64dp&quot;
167a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy *     android:width=&quot;64dp&quot;
168a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy *     android:viewportHeight=&quot;600&quot;
169a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy *     android:viewportWidth=&quot;600&quot; &gt;
170b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy *     &lt;group
171b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy *         android:name=&quot;rotationGroup&quot;
172c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy *         android:pivotX=&quot;300.0&quot;
173c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy *         android:pivotY=&quot;300.0&quot;
174e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy *         android:rotation=&quot;45.0&quot; &gt;
175e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy *         &lt;path
176e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy *             android:name=&quot;v&quot;
177e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy *             android:fillColor=&quot;#000000&quot;
178c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
179b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy *     &lt;/group&gt;
180b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy * &lt;/vector&gt;
1816c319ca1275c8db892c39b48fc54864c949f9171Romain Guy * </pre></li>
182da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy */
183da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
184da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guypublic class VectorDrawable extends Drawable {
185da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final String LOGTAG = VectorDrawable.class.getSimpleName();
186da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
187da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final String SHAPE_CLIP_PATH = "clip-path";
18850c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy    private static final String SHAPE_GROUP = "group";
189da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final String SHAPE_PATH = "path";
190da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final String SHAPE_VECTOR = "vector";
1916c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
1926c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    private static final int LINECAP_BUTT = 0;
1936c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    private static final int LINECAP_ROUND = 1;
1946c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    private static final int LINECAP_SQUARE = 2;
1956c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
196eb99356a0548684a501766e6a524529ab93304c8Romain Guy    private static final int LINEJOIN_MITER = 0;
197da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final int LINEJOIN_ROUND = 1;
198da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final int LINEJOIN_BEVEL = 2;
199746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy
200da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private static final boolean DBG_VECTOR_DRAWABLE = false;
201f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy
202f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    private VectorDrawableState mVectorState;
20342f3a4b7c35dd1ea1922356eb3611af8cde05179Romain Guy
20403750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy    private PorterDuffColorFilter mTintFilter;
20550c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy    private ColorFilter mColorFilter;
20650c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy
20750c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy    private boolean mMutated;
20850c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy
20950c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy    // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise,
210da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    // caching the bitmap by default is allowed.
211da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private boolean mAllowCaching = true;
2126c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
2136c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    public VectorDrawable() {
2146c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        mVectorState = new VectorDrawableState();
2156c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
216f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
217f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private VectorDrawable(@NonNull VectorDrawableState state) {
218f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        mVectorState = state;
219f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
220bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    }
2217ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy
222bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    @Override
223bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    public Drawable mutate() {
224bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        if (!mMutated && super.mutate() == this) {
2258aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            mVectorState = new VectorDrawableState(mVectorState);
226bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy            mMutated = true;
227bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        }
228bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return this;
2292542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    }
2302542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy
2317ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    /**
232bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy     * @hide
233bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy     */
234bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    public void clearMutated() {
2358fb954263dd2f918ad339045cc6d82e346515599Romain Guy        super.clearMutated();
236bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        mMutated = false;
2378fb954263dd2f918ad339045cc6d82e346515599Romain Guy    }
2382542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy
2397ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    Object getTargetByName(String name) {
240bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
241bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    }
2428aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy
2438aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    @Override
2448fb954263dd2f918ad339045cc6d82e346515599Romain Guy    public ConstantState getConstantState() {
245bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        mVectorState.mChangingConfigurations = getChangingConfigurations();
246bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return mVectorState;
247bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    }
2487ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy
249bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    @Override
250eb99356a0548684a501766e6a524529ab93304c8Romain Guy    public void draw(Canvas canvas) {
251bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        final Rect bounds = getBounds();
252bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        if (bounds.width() <= 0 || bounds.height() <= 0) {
2537ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy            // Nothing to draw
254bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            return;
255eb99356a0548684a501766e6a524529ab93304c8Romain Guy        }
256eb99356a0548684a501766e6a524529ab93304c8Romain Guy
257eb99356a0548684a501766e6a524529ab93304c8Romain Guy        final int saveCount = canvas.save();
258eb99356a0548684a501766e6a524529ab93304c8Romain Guy        final boolean needMirroring = needMirroring();
259eb99356a0548684a501766e6a524529ab93304c8Romain Guy
260eb99356a0548684a501766e6a524529ab93304c8Romain Guy        canvas.translate(bounds.left, bounds.top);
2618b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy        if (needMirroring) {
2628b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy            canvas.translate(bounds.width(), 0);
2638b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy            canvas.scale(-1.0f, 1.0f);
2642542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        }
265746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy
2668fb954263dd2f918ad339045cc6d82e346515599Romain Guy        // Color filters always override tint filters.
2672542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        final ColorFilter colorFilter = mColorFilter == null ? mTintFilter : mColorFilter;
2685ec9924d24495822b589f1a17996655d66273b30Romain Guy
2695ec9924d24495822b589f1a17996655d66273b30Romain Guy        if (!mAllowCaching) {
2705ec9924d24495822b589f1a17996655d66273b30Romain Guy            // AnimatedVectorDrawable
2715ec9924d24495822b589f1a17996655d66273b30Romain Guy            if (!mVectorState.hasTranslucentRoot()) {
2722542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy                mVectorState.mVPathRenderer.draw(
273d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy                        canvas, bounds.width(), bounds.height(), colorFilter);
2745cbbce535744b89df5ecea95de21ee3733298260Romain Guy            } else {
275f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy                mVectorState.createCachedBitmapIfNeeded(bounds);
276bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy                mVectorState.updateCachedBitmap(bounds);
277bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy                mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
278bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            }
279bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        } else {
2805c13d89c1332fcc499379b9064b891187b75ca32Chet Haase            // Static Vector Drawable case.
281eb99356a0548684a501766e6a524529ab93304c8Romain Guy            mVectorState.createCachedBitmapIfNeeded(bounds);
282eb99356a0548684a501766e6a524529ab93304c8Romain Guy            if (!mVectorState.canReuseCache()) {
283d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy                mVectorState.updateCachedBitmap(bounds);
284af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy                mVectorState.updateCacheStates();
285e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy            }
286e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy            mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
287e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy        }
288e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
289e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy        canvas.restoreToCount(saveCount);
290e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    }
291e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
292e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    @Override
293e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    public int getAlpha() {
294e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy        return mVectorState.mVPathRenderer.getRootAlpha();
295e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    }
296e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
297e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    @Override
298a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy    public void setAlpha(int alpha) {
299a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
300e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy            mVectorState.mVPathRenderer.setRootAlpha(alpha);
301d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy            invalidateSelf();
302d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        }
303dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
304dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
305d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    @Override
306d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    public void setColorFilter(ColorFilter colorFilter) {
307bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        mColorFilter = colorFilter;
308bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        invalidateSelf();
309bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    }
310bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
3115b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    @Override
3128aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    public void setTintList(ColorStateList tint) {
3138b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy        final VectorDrawableState state = mVectorState;
3148aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        if (state.mTint != tint) {
3158aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            state.mTint = tint;
3168aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            mTintFilter = updateTintFilter(mTintFilter, tint, state.mTintMode);
3178b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy            invalidateSelf();
318d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        }
319bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    }
3201c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3211c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    @Override
3221c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    public void setTintMode(Mode tintMode) {
3231c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        final VectorDrawableState state = mVectorState;
3241c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        if (state.mTintMode != tintMode) {
3251c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy            state.mTintMode = tintMode;
3261c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy            mTintFilter = updateTintFilter(mTintFilter, state.mTint, tintMode);
3271c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy            invalidateSelf();
3281c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        }
3291c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    }
3301c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3311c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    @Override
3321c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    public boolean isStateful() {
3331c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        return super.isStateful() || (mVectorState != null && mVectorState.mTint != null
3341c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy                && mVectorState.mTint.isStateful());
3351c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    }
3361c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3376b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    @Override
3386b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    protected boolean onStateChange(int[] stateSet) {
3396b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy        final VectorDrawableState state = mVectorState;
3406b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy        if (state.mTint != null && state.mTintMode != null) {
3411c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
3421c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy            invalidateSelf();
3431c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy            return true;
3441c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        }
34587a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy        return false;
3461c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    }
3471c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3481c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    @Override
3491c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    public int getOpacity() {
3501c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        return PixelFormat.TRANSLUCENT;
3511c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    }
3521c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3531c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    @Override
3541c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    public int getIntrinsicWidth() {
3551c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        return (int) mVectorState.mVPathRenderer.mBaseWidth;
3561c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    }
3571c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3581c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    @Override
3591c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    public int getIntrinsicHeight() {
3601c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        return (int) mVectorState.mVPathRenderer.mBaseHeight;
3611c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    }
3621c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
3631c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    @Override
3641c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    public boolean canApplyTheme() {
36587a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy        return (mVectorState != null && mVectorState.canApplyTheme()) || super.canApplyTheme();
36687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    }
36787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy
36887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    @Override
36987a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy    public void applyTheme(Theme t) {
3701c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        super.applyTheme(t);
371d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
372eb99356a0548684a501766e6a524529ab93304c8Romain Guy        final VectorDrawableState state = mVectorState;
373eb99356a0548684a501766e6a524529ab93304c8Romain Guy        if (state == null) {
374eb99356a0548684a501766e6a524529ab93304c8Romain Guy            return;
375fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
376dda570201ac851dd85af3861f7e575721d3345daRomain Guy
377eb99356a0548684a501766e6a524529ab93304c8Romain Guy        if (state.mThemeAttrs != null) {
378eb99356a0548684a501766e6a524529ab93304c8Romain Guy            final TypedArray a = t.resolveAttributes(
379f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy                    state.mThemeAttrs, R.styleable.VectorDrawable);
3808aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            try {
381ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy                state.mCacheDirty = true;
382ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy                updateStateFromTypedArray(a);
383ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy            } catch (XmlPullParserException e) {
384ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy                throw new RuntimeException(e);
385eb99356a0548684a501766e6a524529ab93304c8Romain Guy            } finally {
386ae517591d96be39f5f18a1716c856ade13a8bcc7Romain Guy                a.recycle();
387eb99356a0548684a501766e6a524529ab93304c8Romain Guy            }
38858ae6db4ff8a9d0910e1183ee8be9a038a2712a6Romain Guy        }
389ae517591d96be39f5f18a1716c856ade13a8bcc7Romain Guy
390ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy        // Apply theme to contained color state list.
391ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy        if (state.mTint != null && state.mTint.canApplyTheme()) {
392ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy            state.mTint.applyTheme(t);
393ae517591d96be39f5f18a1716c856ade13a8bcc7Romain Guy        }
394ae517591d96be39f5f18a1716c856ade13a8bcc7Romain Guy
395ae517591d96be39f5f18a1716c856ade13a8bcc7Romain Guy        final VPathRenderer path = state.mVPathRenderer;
396ae517591d96be39f5f18a1716c856ade13a8bcc7Romain Guy        if (path != null && path.canApplyTheme()) {
397eb99356a0548684a501766e6a524529ab93304c8Romain Guy            path.applyTheme(t);
398bf434114cbf55b216fdc76fc8d65a75e84c9dab5Romain Guy        }
399746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy
400746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        // Update local state.
40132963c393a804db2cd86c24443c2f1c6eee6064bRomain Guy        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
402dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
403e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
404dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    /**
405dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy     * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension.
406dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy     * This is used to calculate the path animation accuracy.
407af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy     *
408b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy     * @hide
409b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy     */
410dda570201ac851dd85af3861f7e575721d3345daRomain Guy    public float getPixelSize() {
4115b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (mVectorState == null || mVectorState.mVPathRenderer == null ||
4128550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy                mVectorState.mVPathRenderer.mBaseWidth == 0 ||
413f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy                mVectorState.mVPathRenderer.mBaseHeight == 0 ||
414f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy                mVectorState.mVPathRenderer.mViewportHeight == 0 ||
415bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy                mVectorState.mVPathRenderer.mViewportWidth == 0) {
416bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            return 1; // fall back to 1:1 pixel mapping.
417dda570201ac851dd85af3861f7e575721d3345daRomain Guy        }
418f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
4198aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
4208550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
4218550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy        float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
422171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy        float scaleX = viewportWidth / intrinsicWidth;
423dda570201ac851dd85af3861f7e575721d3345daRomain Guy        float scaleY = viewportHeight / intrinsicHeight;
4248fb954263dd2f918ad339045cc6d82e346515599Romain Guy        return Math.min(scaleX, scaleY);
4258fb954263dd2f918ad339045cc6d82e346515599Romain Guy    }
426dda570201ac851dd85af3861f7e575721d3345daRomain Guy
4271d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    /** @hide */
428eb99356a0548684a501766e6a524529ab93304c8Romain Guy    public static VectorDrawable create(Resources resources, int rid) {
4295b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        try {
430eb99356a0548684a501766e6a524529ab93304c8Romain Guy            final XmlPullParser parser = resources.getXml(rid);
431eb99356a0548684a501766e6a524529ab93304c8Romain Guy            final AttributeSet attrs = Xml.asAttributeSet(parser);
432eb99356a0548684a501766e6a524529ab93304c8Romain Guy            int type;
433514fb18827186591d66973c2362c859b64b63556Romain Guy            while ((type=parser.next()) != XmlPullParser.START_TAG &&
434514fb18827186591d66973c2362c859b64b63556Romain Guy                    type != XmlPullParser.END_DOCUMENT) {
435514fb18827186591d66973c2362c859b64b63556Romain Guy                // Empty loop
436514fb18827186591d66973c2362c859b64b63556Romain Guy            }
437514fb18827186591d66973c2362c859b64b63556Romain Guy            if (type != XmlPullParser.START_TAG) {
438514fb18827186591d66973c2362c859b64b63556Romain Guy                throw new XmlPullParserException("No start tag found");
439514fb18827186591d66973c2362c859b64b63556Romain Guy            }
440514fb18827186591d66973c2362c859b64b63556Romain Guy
441514fb18827186591d66973c2362c859b64b63556Romain Guy            final VectorDrawable drawable = new VectorDrawable();
442514fb18827186591d66973c2362c859b64b63556Romain Guy            drawable.inflate(resources, parser, attrs);
443514fb18827186591d66973c2362c859b64b63556Romain Guy
444ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy            return drawable;
445eb99356a0548684a501766e6a524529ab93304c8Romain Guy        } catch (XmlPullParserException e) {
446f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            Log.e(LOGTAG, "parser error", e);
447d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        } catch (IOException e) {
448bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            Log.e(LOGTAG, "parser error", e);
449bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        }
4505b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        return null;
4515b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
4525b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4535b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    private static int applyAlpha(int color, float alpha) {
4545b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        int alphaBytes = Color.alpha(color);
4555b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        color &= 0x00FFFFFF;
4565b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        color |= ((int) (alphaBytes * alpha)) << 24;
4575b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        return color;
4585b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
4595b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    @Override
4615b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
4625b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            throws XmlPullParserException, IOException {
4635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final VectorDrawableState state = mVectorState;
4645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final VPathRenderer pathRenderer = new VPathRenderer();
4655b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        state.mVPathRenderer = pathRenderer;
4665b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4675b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
4685b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        updateStateFromTypedArray(a);
4695b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        a.recycle();
4705b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4715ec9924d24495822b589f1a17996655d66273b30Romain Guy        state.mCacheDirty = true;
4725b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        inflateInternal(res, parser, attrs, theme);
4735b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4745b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
4755b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
4765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
4785b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final VectorDrawableState state = mVectorState;
4795b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final VPathRenderer pathRenderer = state.mVPathRenderer;
4805b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4815b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Account for any configuration changes.
4825b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        state.mChangingConfigurations |= a.getChangingConfigurations();
4835b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4845b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Extract the theme attributes, if any.
4855b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        state.mThemeAttrs = a.extractThemeAttrs();
4865b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4875b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
4885b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (tintMode != -1) {
4895b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
4905b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
4915b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4925b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
4935b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (tint != null) {
4945b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            state.mTint = tint;
4955b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
4965b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
4975b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        state.mAutoMirrored = a.getBoolean(
4985b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
4995b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5005b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        pathRenderer.mViewportWidth = a.getFloat(
5015b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
5025b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        pathRenderer.mViewportHeight = a.getFloat(
5035b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
5045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5055b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (pathRenderer.mViewportWidth <= 0) {
5065b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            throw new XmlPullParserException(a.getPositionDescription() +
5075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    "<vector> tag requires viewportWidth > 0");
5085b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        } else if (pathRenderer.mViewportHeight <= 0) {
5095b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            throw new XmlPullParserException(a.getPositionDescription() +
5105b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    "<vector> tag requires viewportHeight > 0");
5115b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
5125b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5135b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        pathRenderer.mBaseWidth = a.getDimension(
5145b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
5155b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        pathRenderer.mBaseHeight = a.getDimension(
5165b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
5175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (pathRenderer.mBaseWidth <= 0) {
5195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            throw new XmlPullParserException(a.getPositionDescription() +
5205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    "<vector> tag requires width > 0");
5215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        } else if (pathRenderer.mBaseHeight <= 0) {
5225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            throw new XmlPullParserException(a.getPositionDescription() +
5235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    "<vector> tag requires height > 0");
5245b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
5255b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5261c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
5271c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy                pathRenderer.getAlpha());
5281c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        pathRenderer.setAlpha(alphaInFloat);
5291d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
5301d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        final String name = a.getString(R.styleable.VectorDrawable_name);
5311d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        if (name != null) {
5321d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy            pathRenderer.mRootName = name;
5331d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy            pathRenderer.mVGTargetsMap.put(name, pathRenderer);
5341d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        }
5355b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
536eb99356a0548684a501766e6a524529ab93304c8Romain Guy
537eb99356a0548684a501766e6a524529ab93304c8Romain Guy    private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
538eb99356a0548684a501766e6a524529ab93304c8Romain Guy            Theme theme) throws XmlPullParserException, IOException {
539eb99356a0548684a501766e6a524529ab93304c8Romain Guy        final VectorDrawableState state = mVectorState;
540eb99356a0548684a501766e6a524529ab93304c8Romain Guy        final VPathRenderer pathRenderer = state.mVPathRenderer;
541eb99356a0548684a501766e6a524529ab93304c8Romain Guy        boolean noPathTag = true;
5421d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
5431d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        // Use a stack to help to build the group tree.
5441d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        // The top of the stack is always the current group.
545eb99356a0548684a501766e6a524529ab93304c8Romain Guy        final Stack<VGroup> groupStack = new Stack<VGroup>();
546f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        groupStack.push(pathRenderer.mRootGroup);
5471c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy
5485b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        int eventType = parser.getEventType();
5495b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        while (eventType != XmlPullParser.END_DOCUMENT) {
550f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy            if (eventType == XmlPullParser.START_TAG) {
551f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy                final String tagName = parser.getName();
55203750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy                final VGroup currentGroup = groupStack.peek();
5538b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
554746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy                if (SHAPE_PATH.equals(tagName)) {
5555b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    final VFullPath path = new VFullPath();
5565b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    path.inflate(res, attrs, theme);
5575b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    currentGroup.mChildren.add(path);
558eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    if (path.getPathName() != null) {
5595b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
560171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                    }
561171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                    noPathTag = false;
562171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                    state.mChangingConfigurations |= path.mChangingConfigurations;
5635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                } else if (SHAPE_CLIP_PATH.equals(tagName)) {
564171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                    final VClipPath path = new VClipPath();
565171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                    path.inflate(res, attrs, theme);
566171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                    currentGroup.mChildren.add(path);
567eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    if (path.getPathName() != null) {
568514fb18827186591d66973c2362c859b64b63556Romain Guy                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
569514fb18827186591d66973c2362c859b64b63556Romain Guy                    }
570514fb18827186591d66973c2362c859b64b63556Romain Guy                    state.mChangingConfigurations |= path.mChangingConfigurations;
571514fb18827186591d66973c2362c859b64b63556Romain Guy                } else if (SHAPE_GROUP.equals(tagName)) {
572eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    VGroup newChildGroup = new VGroup();
5731d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy                    newChildGroup.inflate(res, attrs, theme);
574eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    currentGroup.mChildren.add(newChildGroup);
575eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    groupStack.push(newChildGroup);
576eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    if (newChildGroup.getGroupName() != null) {
577eb99356a0548684a501766e6a524529ab93304c8Romain Guy                        pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
578eb99356a0548684a501766e6a524529ab93304c8Romain Guy                                newChildGroup);
579eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    }
580eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
581eb99356a0548684a501766e6a524529ab93304c8Romain Guy                }
582eb99356a0548684a501766e6a524529ab93304c8Romain Guy            } else if (eventType == XmlPullParser.END_TAG) {
583eb99356a0548684a501766e6a524529ab93304c8Romain Guy                final String tagName = parser.getName();
584746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy                if (SHAPE_GROUP.equals(tagName)) {
585746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy                    groupStack.pop();
586eb99356a0548684a501766e6a524529ab93304c8Romain Guy                }
5878550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy            }
5881d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy            eventType = parser.next();
5891d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        }
5901d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
5911d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        // Print the tree out for debug.
5921d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        if (DBG_VECTOR_DRAWABLE) {
5931d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy            printGroupTree(pathRenderer.mRootGroup, 0);
5945b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
5955b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5965b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (noPathTag) {
5975b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            final StringBuffer tag = new StringBuffer();
5985b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
5995b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            if (tag.length() > 0) {
6005b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                tag.append(" or ");
6015b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
6025b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            tag.append(SHAPE_PATH);
6035b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            throw new XmlPullParserException("no " + tag + " defined");
6055b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
6065b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
6075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6085b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    private void printGroupTree(VGroup currentGroup, int level) {
6095b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        String indent = "";
6105b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        for (int i = 0; i < level; i++) {
6115b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            indent += "    ";
6125b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
6135b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Print the current node
6145b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
6155b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                + " rotation is " + currentGroup.mRotate);
6165b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
6175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Then print all the children groups
6185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        for (int i = 0; i < currentGroup.mChildren.size(); i++) {
6195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            Object child = currentGroup.mChildren.get(i);
620f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy            if (child instanceof VGroup) {
6215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                printGroupTree((VGroup) child, level + 1);
6225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
6235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
6245b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
6257230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
6267230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    @Override
6277230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    public int getChangingConfigurations() {
628ada830f639591b99c3e40de22b07296c7932a33fRomain Guy        return super.getChangingConfigurations() | mVectorState.mChangingConfigurations;
6297230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    }
6307230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
6317230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    void setAllowCaching(boolean allowCaching) {
6327230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        mAllowCaching = allowCaching;
633ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    }
6347230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
635c038ea358aadca082198f3effc550d33135bf426Romain Guy    private boolean needMirroring() {
6367230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
6375b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
6385b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6395b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    @Override
6405b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    public void setAutoMirrored(boolean mirrored) {
6415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        if (mVectorState.mAutoMirrored != mirrored) {
642f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy            mVectorState.mAutoMirrored = mirrored;
6435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            invalidateSelf();
644f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy        }
6455b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
6465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    @Override
6485b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    public boolean isAutoMirrored() {
6495b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        return mVectorState.mAutoMirrored;
6505b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
6515b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6525b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    private static class VectorDrawableState extends ConstantState {
6535b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        int[] mThemeAttrs;
6545b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        int mChangingConfigurations;
6555b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        VPathRenderer mVPathRenderer;
6565b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        ColorStateList mTint = null;
6575b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Mode mTintMode = DEFAULT_TINT_MODE;
6585b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        boolean mAutoMirrored;
6595b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Bitmap mCachedBitmap;
6615b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        int[] mCachedThemeAttrs;
6625b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        ColorStateList mCachedTint;
6635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Mode mCachedTintMode;
6645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        int mCachedRootAlpha;
6655b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        boolean mCachedAutoMirrored;
6667230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        boolean mCacheDirty;
6675b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6685b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        /** Temporary paint object used to draw cached bitmaps. */
6695b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Paint mTempPaint;
6705b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6715b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Deep copy for mutate() or implicitly mutate.
6725b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public VectorDrawableState(VectorDrawableState copy) {
6735b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            if (copy != null) {
6745b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mThemeAttrs = copy.mThemeAttrs;
6755b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mChangingConfigurations = copy.mChangingConfigurations;
6765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
6775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                if (copy.mVPathRenderer.mFillPaint != null) {
6785b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
6795b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                }
6805b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                if (copy.mVPathRenderer.mStrokePaint != null) {
6815b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
6825b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                }
6835b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mTint = copy.mTint;
6845b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mTintMode = copy.mTintMode;
6855b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mAutoMirrored = copy.mAutoMirrored;
6865b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
6875b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
6885b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6895b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter) {
6905b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            // The bitmap's size is the same as the bounds.
6915b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            final Paint p = getPaint(filter);
6925b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            canvas.drawBitmap(mCachedBitmap, 0, 0, p);
6935b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
6945b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6955b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public boolean hasTranslucentRoot() {
6965b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            return mVPathRenderer.getRootAlpha() < 255;
6975b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
6985b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6995b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        /**
700f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy         * @return null when there is no need for alpha paint.
7015b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy         */
7025b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public Paint getPaint(ColorFilter filter) {
703f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy            if (!hasTranslucentRoot() && filter == null) {
7045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                return null;
7055b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
7065b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            if (mTempPaint == null) {
7085b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mTempPaint = new Paint();
7095b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mTempPaint.setFilterBitmap(true);
7105b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
711f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy            mTempPaint.setAlpha(mVPathRenderer.getRootAlpha());
7125b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            mTempPaint.setColorFilter(filter);
713f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy            return mTempPaint;
7141bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        }
7151bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy
7161bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        public void updateCachedBitmap(Rect bounds) {
7171bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy            mCachedBitmap.eraseColor(Color.TRANSPARENT);
7181bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy            Canvas tmpCanvas = new Canvas(mCachedBitmap);
7191bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy            mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height(), null);
7201bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        }
7211bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy
7221bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        public void createCachedBitmapIfNeeded(Rect bounds) {
7231bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy            if (mCachedBitmap == null || !canReuseBitmap(bounds.width(),
7241bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy                    bounds.height())) {
7255b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
7265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                        Bitmap.Config.ARGB_8888);
7275b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                mCacheDirty = true;
7285b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
7295b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7308694230ff25fa0a60e480d424843e56b718f0516Romain Guy        }
731af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy
7328694230ff25fa0a60e480d424843e56b718f0516Romain Guy        public boolean canReuseBitmap(int width, int height) {
7335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            if (width == mCachedBitmap.getWidth()
7345b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    && height == mCachedBitmap.getHeight()) {
7355b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                return true;
7368694230ff25fa0a60e480d424843e56b718f0516Romain Guy            }
7378694230ff25fa0a60e480d424843e56b718f0516Romain Guy            return false;
7385b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
7395b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7405b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public boolean canReuseCache() {
7415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            if (!mCacheDirty
7425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    && mCachedThemeAttrs == mThemeAttrs
7435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    && mCachedTint == mTint
7445b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    && mCachedTintMode == mTintMode
7455b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    && mCachedAutoMirrored == mAutoMirrored
7465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
7475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                return true;
7488694230ff25fa0a60e480d424843e56b718f0516Romain Guy            }
7498694230ff25fa0a60e480d424843e56b718f0516Romain Guy            return false;
7508694230ff25fa0a60e480d424843e56b718f0516Romain Guy        }
7518694230ff25fa0a60e480d424843e56b718f0516Romain Guy
7525b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public void updateCacheStates() {
7538694230ff25fa0a60e480d424843e56b718f0516Romain Guy            // Use shallow copy here and shallow comparison in canReuseCache(),
7548694230ff25fa0a60e480d424843e56b718f0516Romain Guy            // likely hit cache miss more, but practically not much difference.
755bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            mCachedThemeAttrs = mThemeAttrs;
756f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            mCachedTint = mTint;
757f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            mCachedTintMode = mTintMode;
758f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            mCachedRootAlpha = mVPathRenderer.getRootAlpha();
759f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            mCachedAutoMirrored = mAutoMirrored;
7608aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            mCacheDirty = false;
761f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
762f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
763f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        @Override
7648aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        public boolean canApplyTheme() {
765f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            return mThemeAttrs != null
766f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy                    || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
767f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy                    || (mTint != null && mTint.canApplyTheme())
7688aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy                    || super.canApplyTheme();
769f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
770f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
771807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy        public VectorDrawableState() {
772807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy            mVPathRenderer = new VPathRenderer();
773807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy        }
774807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy
775f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        @Override
7768aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        public Drawable newDrawable() {
777f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy            return new VectorDrawable(this);
778f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
77941030da16856c8869e1e51d4a0405432fa96614eRomain Guy
78099bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy        @Override
78199bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy        public Drawable newDrawable(Resources res) {
78299bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy            return new VectorDrawable(this);
78399bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy        }
78441030da16856c8869e1e51d4a0405432fa96614eRomain Guy
78541030da16856c8869e1e51d4a0405432fa96614eRomain Guy        @Override
786f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        public int getChangingConfigurations() {
7878aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            return mChangingConfigurations;
788f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
789f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    }
790f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
791e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    private static class VPathRenderer {
792e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy        /* Right now the internal data structure is organized as a tree.
793e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy         * Each node can be a group node, or a path.
794e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy         * A group node can have groups or paths as children, but a path node has
795f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy         * no children.
796f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy         * One example can be:
797f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy         *                 Root Group
798f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy         *                /    |     \
799f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy         *           Group    Path    Group
800f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy         *          /     \             |
801bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy         *         Path   Path         Path
802e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy         *
803e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy         */
804eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Variables that only used temporarily inside the draw() call, so there
805746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        // is no need for deep copying.
8069d5316e3f56d138504565ff311145ac01621dff4Romain Guy        private final Path mPath;
8079d5316e3f56d138504565ff311145ac01621dff4Romain Guy        private final Path mRenderPath;
8089d5316e3f56d138504565ff311145ac01621dff4Romain Guy        private final Matrix mFinalPathMatrix = new Matrix();
809079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy
810bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        private Paint mStrokePaint;
811bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        private Paint mFillPaint;
812c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        private PathMeasure mPathMeasure;
813af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy
814dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        /////////////////////////////////////////////////////
815dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        // Variables below need to be copied (deep copy if applicable) for mutation.
816dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        private int mChangingConfigurations;
8171d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        private final VGroup mRootGroup;
8188aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        float mBaseWidth = 0;
819d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        float mBaseHeight = 0;
820d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        float mViewportWidth = 0;
821d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        float mViewportHeight = 0;
822d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        int mRootAlpha = 0xFF;
823d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        String mRootName = null;
824d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy
825c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
826c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
827079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        public VPathRenderer() {
828079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy            mRootGroup = new VGroup();
8297ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy            mPath = new Path();
830746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy            mRenderPath = new Path();
8317ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy        }
8328aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy
833e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        public void setRootAlpha(int alpha) {
834e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            mRootAlpha = alpha;
835f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
83670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
83770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        public int getRootAlpha() {
83870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            return mRootAlpha;
83970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        }
84070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
84170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        // setAlpha() and getAlpha() are used mostly for animation purpose, since
84270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        // Animator like to use alpha from 0 to 1.
84370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        public void setAlpha(float alpha) {
84470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            setRootAlpha((int) (alpha * 255));
84570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        }
84670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
84770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        @SuppressWarnings("unused")
84870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        public float getAlpha() {
84970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            return getRootAlpha() / 255.0f;
8508d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy        }
85170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
85270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        public VPathRenderer(VPathRenderer copy) {
85370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
85470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mPath = new Path(copy.mPath);
85570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mRenderPath = new Path(copy.mRenderPath);
85670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mBaseWidth = copy.mBaseWidth;
85770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mBaseHeight = copy.mBaseHeight;
85870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mViewportWidth = copy.mViewportWidth;
8598d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mViewportHeight = copy.mViewportHeight;
8608d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mChangingConfigurations = copy.mChangingConfigurations;
8618d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mRootAlpha = copy.mRootAlpha;
8628d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mRootName = copy.mRootName;
8638d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            if (copy.mRootName != null) {
86470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                mVGTargetsMap.put(copy.mRootName, this);
865fa7952dbb86a8aff0c90418aa77dddee3802c23aRomain Guy            }
866fa7952dbb86a8aff0c90418aa77dddee3802c23aRomain Guy        }
867fa7952dbb86a8aff0c90418aa77dddee3802c23aRomain Guy
86870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        public boolean canApplyTheme() {
86970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // If one of the paths can apply theme, then return true;
87070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            return recursiveCanApplyTheme(mRootGroup);
87170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        }
87286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
87386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        private boolean recursiveCanApplyTheme(VGroup currentGroup) {
87486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            // We can do a tree traverse here, if there is one path return true,
87586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            // then we return true for the whole tree.
87686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            final ArrayList<Object> children = currentGroup.mChildren;
87786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
87886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            for (int i = 0; i < children.size(); i++) {
87986568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                Object child = children.get(i);
88086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                if (child instanceof VGroup) {
88186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                    VGroup childGroup = (VGroup) child;
88270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (childGroup.canApplyTheme()
88370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                            || recursiveCanApplyTheme(childGroup)) {
88470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        return true;
88570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
88670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                } else if (child instanceof VPath) {
88770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    VPath childPath = (VPath) child;
88870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (childPath.canApplyTheme()) {
88970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        return true;
89070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
89186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                }
89286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            }
89386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            return false;
89486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
89586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
89686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        public void applyTheme(Theme t) {
89786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            // Apply theme to every path of the tree.
89886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            recursiveApplyTheme(mRootGroup, t);
89986568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
90070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
90170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
90270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // We can do a tree traverse here, apply theme to all paths which
90370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // can apply theme.
90470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            final ArrayList<Object> children = currentGroup.mChildren;
90570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            for (int i = 0; i < children.size(); i++) {
90670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                Object child = children.get(i);
90770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                if (child instanceof VGroup) {
90870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    VGroup childGroup = (VGroup) child;
90970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (childGroup.canApplyTheme()) {
91070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        childGroup.applyTheme(t);
91170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
91270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    recursiveApplyTheme(childGroup, t);
91370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                } else if (child instanceof VPath) {
91470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    VPath childPath = (VPath) child;
91570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (childPath.canApplyTheme()) {
91670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        childPath.applyTheme(t);
91770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
91870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                }
91970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            }
92070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        }
92170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
92270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
92370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                Canvas canvas, int w, int h, ColorFilter filter) {
92470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // Calculate current group's matrix by preConcat the parent's and
92570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // and the current one on the top of the stack.
92670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
92770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // Mi the local matrix at level i of the group tree.
92870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            currentGroup.mStackedMatrix.set(currentMatrix);
92970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
93070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
93170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // Save the current clip information, which is local to this group.
93270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            canvas.save();
93370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // Draw the group tree in the same order as the XML file.
93470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            for (int i = 0; i < currentGroup.mChildren.size(); i++) {
93570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                Object child = currentGroup.mChildren.get(i);
93670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                if (child instanceof VGroup) {
93770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    VGroup childGroup = (VGroup) child;
93870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    drawGroupTree(childGroup, currentGroup.mStackedMatrix,
93970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                            canvas, w, h, filter);
94070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                } else if (child instanceof VPath) {
94170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    VPath childPath = (VPath) child;
9428d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                    drawPath(currentGroup, childPath, canvas, w, h, filter);
9438d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                }
9448d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            }
9458d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            canvas.restore();
94670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        }
94770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
94870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
94970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            // Travese the tree in pre-order to draw.
95070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvas, w, h, filter);
95170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        }
95270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
95370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h,
95486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                ColorFilter filter) {
95586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            final float scaleX = w / mViewportWidth;
95686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            final float scaleY = h / mViewportHeight;
95786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            final float minScale = Math.min(scaleX, scaleY);
95886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
95986568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            mFinalPathMatrix.set(vGroup.mStackedMatrix);
96086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            mFinalPathMatrix.postScale(scaleX, scaleY);
96186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
96286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            vPath.toPath(mPath);
96386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            final Path path = mPath;
96470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
96570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            mRenderPath.reset();
96670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
9675536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy            if (vPath.isClipPath()) {
96870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                mRenderPath.addPath(path, mFinalPathMatrix);
96970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
97070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            } else {
97170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                VFullPath fullPath = (VFullPath) vPath;
97286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
9735536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy                    float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
97486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy                    float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
9755536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy
9765536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy                    if (mPathMeasure == null) {
9775536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy                        mPathMeasure = new PathMeasure();
97870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
97970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    mPathMeasure.setPath(mPath, false);
98070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
98170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    float len = mPathMeasure.getLength();
98270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    start = start * len;
98370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    end = end * len;
98470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    path.reset();
98570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (start > end) {
98670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mPathMeasure.getSegment(start, len, path, true);
9878d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                        mPathMeasure.getSegment(0f, end, path, true);
9888d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                    } else {
9898d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                        mPathMeasure.getSegment(start, end, path, true);
9908d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                    }
9918d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                    path.rLineTo(0, 0); // fix bug in measure
9928d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                }
99370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                mRenderPath.addPath(path, mFinalPathMatrix);
99470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
99570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                if (fullPath.mFillColor != Color.TRANSPARENT) {
99670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (mFillPaint == null) {
99770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mFillPaint = new Paint();
99870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mFillPaint.setStyle(Paint.Style.FILL);
99970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mFillPaint.setAntiAlias(true);
100070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
100170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
100270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    final Paint fillPaint = mFillPaint;
100370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
100470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    fillPaint.setColorFilter(filter);
100570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    canvas.drawPath(mRenderPath, fillPaint);
100670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                }
100770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
100870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                if (fullPath.mStrokeColor != Color.TRANSPARENT) {
100970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (mStrokePaint == null) {
101070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mStrokePaint = new Paint();
101170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mStrokePaint.setStyle(Paint.Style.STROKE);
101270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        mStrokePaint.setAntiAlias(true);
101370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
101470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
101570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    final Paint strokePaint = mStrokePaint;
101670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (fullPath.mStrokeLineJoin != null) {
101770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                        strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
101870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    }
101970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
102070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    if (fullPath.mStrokeLineCap != null) {
10218d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                        strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
10228d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy                    }
10238d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy
102470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
102570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
102670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    strokePaint.setColorFilter(filter);
102770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale);
102870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                    canvas.drawPath(mRenderPath, strokePaint);
102970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy                }
103070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy            }
1031f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        }
1032f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    }
1033f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1034ffac7fc5042296a459d0f5a450dbfe20917093dcRomain Guy    private static class VGroup {
10350fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy        // mStackedMatrix is only used temporarily when drawing, it combines all
10360fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy        // the parents' local matrices with the current one.
10370fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy        private final Matrix mStackedMatrix = new Matrix();
1038ffac7fc5042296a459d0f5a450dbfe20917093dcRomain Guy
10390fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy        /////////////////////////////////////////////////////
10400fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy        // Variables below need to be copied (deep copy if applicable) for mutation.
10410fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy        final ArrayList<Object> mChildren = new ArrayList<Object>();
10425c13d89c1332fcc499379b9064b891187b75ca32Chet Haase
10436926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mRotate = 0;
10446926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mPivotX = 0;
10456926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mPivotY = 0;
10466926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mScaleX = 1;
10476926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mScaleY = 1;
10486926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mTranslateX = 0;
10496926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private float mTranslateY = 0;
105086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
10518164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy        // mLocalMatrix is updated based on the update of transformation information,
10529cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        // either parsed from the XML or by animation.
105322158e139a3d6c6a9787ca0de224e9368f643284Romain Guy        private final Matrix mLocalMatrix = new Matrix();
105422158e139a3d6c6a9787ca0de224e9368f643284Romain Guy        private int mChangingConfigurations;
10556926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        private int[] mThemeAttrs;
10568ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        private String mGroupName = null;
10578ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
10585c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        public VGroup(VGroup copy, ArrayMap<String, Object> targetsMap) {
1059f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            mRotate = copy.mRotate;
1060f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            mPivotX = copy.mPivotX;
1061f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            mPivotY = copy.mPivotY;
1062f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy            mScaleX = copy.mScaleX;
10636926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            mScaleY = copy.mScaleY;
10646926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            mTranslateX = copy.mTranslateX;
10656926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            mTranslateY = copy.mTranslateY;
10666926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            mThemeAttrs = copy.mThemeAttrs;
106786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            mGroupName = copy.mGroupName;
10688164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy            mChangingConfigurations = copy.mChangingConfigurations;
10699cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy            if (mGroupName != null) {
107022158e139a3d6c6a9787ca0de224e9368f643284Romain Guy                targetsMap.put(mGroupName, this);
107122158e139a3d6c6a9787ca0de224e9368f643284Romain Guy            }
10725b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10735b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            mLocalMatrix.set(copy.mLocalMatrix);
10745b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10755b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            final ArrayList<Object> children = copy.mChildren;
10765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            for (int i = 0; i < children.size(); i++) {
10775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy                Object copyChild = children.get(i);
1078f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                if (copyChild instanceof VGroup) {
1079f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy                    VGroup copyGroup = (VGroup) copyChild;
10805a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    mChildren.add(new VGroup(copyGroup, targetsMap));
10815a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                } else {
10825a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    VPath newPath = null;
10835a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    if (copyChild instanceof VFullPath) {
10845a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                        newPath = new VFullPath((VFullPath) copyChild);
10855a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    } else if (copyChild instanceof VClipPath) {
10865a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                        newPath = new VClipPath((VClipPath) copyChild);
10875a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    } else {
10885a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                        throw new IllegalStateException("Unknown object in the tree!");
10895a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    }
10905a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    mChildren.add(newPath);
10915a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    if (newPath.mPathName != null) {
10925a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                        targetsMap.put(newPath.mPathName, newPath);
10935a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    }
10945a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                }
10955a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            }
10965a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
10975a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
10985a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        public VGroup() {
10995a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
11005a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11015a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        public String getGroupName() {
11025a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            return mGroupName;
11035a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
11045a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11055a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        public Matrix getLocalMatrix() {
11065a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            return mLocalMatrix;
11075a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
11085a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11095a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        public void inflate(Resources res, AttributeSet attrs, Theme theme) {
11105a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            final TypedArray a = obtainAttributes(res, theme, attrs,
11115a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                    R.styleable.VectorDrawableGroup);
11125a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            updateStateFromTypedArray(a);
11135a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            a.recycle();
11145a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
11155a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11165a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        private void updateStateFromTypedArray(TypedArray a) {
11175a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            // Account for any configuration changes.
11185a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mChangingConfigurations |= a.getChangingConfigurations();
11195a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11205a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            // Extract the theme attributes, if any.
11215a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mThemeAttrs = a.extractThemeAttrs();
11225a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11235a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
11245a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
11255a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
11265a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
11275a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
11285a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
11295a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
11305a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
11315a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
11325a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            if (groupName != null) {
11335a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy                mGroupName = groupName;
11345a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            }
11358ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
11368ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            updateLocalMatrix();
11378ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        }
11385c13d89c1332fcc499379b9064b891187b75ca32Chet Haase
11396926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        public boolean canApplyTheme() {
11406926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            return mThemeAttrs != null;
11416926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        }
11426926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
1143746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        public void applyTheme(Theme t) {
11448164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy            if (mThemeAttrs == null) {
11459cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy                return;
114622158e139a3d6c6a9787ca0de224e9368f643284Romain Guy            }
11478164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy
11488ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawableGroup);
11498ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            updateStateFromTypedArray(a);
11508ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            a.recycle();
1151c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        }
11528ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
11538ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        private void updateLocalMatrix() {
11548ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            // The order we apply is the same as the
11558ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            // RenderNode.cpp::applyViewPropertyTransforms().
1156c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy            mLocalMatrix.reset();
115703750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
11588ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            mLocalMatrix.postScale(mScaleX, mScaleY);
11598ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            mLocalMatrix.postRotate(mRotate, 0, 0);
116003750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
116103750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy        }
116203750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy
116303750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
11646620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
11656620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        public float getRotation() {
11666620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            return mRotate;
11676620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
11686620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
11696620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
11706620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        public void setRotation(float rotation) {
11716620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            if (rotation != mRotate) {
11726620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                mRotate = rotation;
11736620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                updateLocalMatrix();
11746620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            }
11756620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
11766620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
11778ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        @SuppressWarnings("unused")
11788ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        public float getPivotX() {
1179ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            return mPivotX;
1180ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        }
11814aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guy
11824bb942083a0d4db746adf95349108dd8ef842e32Romain Guy        @SuppressWarnings("unused")
11835c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        public void setPivotX(float pivotX) {
11846926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            if (pivotX != mPivotX) {
11856926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy                mPivotX = pivotX;
11866926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy                updateLocalMatrix();
11876926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            }
1188746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        }
11898164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy
11909cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        @SuppressWarnings("unused")
119122158e139a3d6c6a9787ca0de224e9368f643284Romain Guy        public float getPivotY() {
11928164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy            return mPivotY;
1193f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy        }
1194f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
1195f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy        @SuppressWarnings("unused")
1196f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy        public void setPivotY(float pivotY) {
1197f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy            if (pivotY != mPivotY) {
11982728f961614a385df1f056fc24803a9f65c90fabRomain Guy                mPivotY = pivotY;
11994bb942083a0d4db746adf95349108dd8ef842e32Romain Guy                updateLocalMatrix();
1200f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy            }
1201a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        }
12026620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
1203a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        @SuppressWarnings("unused")
12045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public float getScaleX() {
12055b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            return mScaleX;
12065b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
12075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
12085b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        @SuppressWarnings("unused")
12098ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy        public void setScaleX(float scaleX) {
12106620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            if (scaleX != mScaleX) {
12116620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                mScaleX = scaleX;
12126620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                updateLocalMatrix();
12138ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy            }
12146620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
12156620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
12166620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
12176620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        public float getScaleY() {
12186620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            return mScaleY;
12195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
12205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
1221a5ef39a21683189e5906c9f252b997f0508e350dRomain Guy        @SuppressWarnings("unused")
12225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        public void setScaleY(float scaleY) {
12236620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            if (scaleY != mScaleY) {
12246620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                mScaleY = scaleY;
12256620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                updateLocalMatrix();
12266620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            }
12276620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
12286620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
12296620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
12306620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        public float getTranslateX() {
12316620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            return mTranslateX;
12326620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
12336620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
12346620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
12356620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        public void setTranslateX(float translateX) {
12366620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            if (translateX != mTranslateX) {
1237054dc1840941665e32036f9523df51720ad069c8Romain Guy                mTranslateX = translateX;
1238f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy                updateLocalMatrix();
1239f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy            }
12405c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        }
1241af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy
1242dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        @SuppressWarnings("unused")
1243a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public float getTranslateY() {
1244a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            return mTranslateY;
1245a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
1246a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1247a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        @SuppressWarnings("unused")
1248a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public void setTranslateY(float translateY) {
1249759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            if (translateY != mTranslateY) {
1250759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy                mTranslateY = translateY;
1251759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy                updateLocalMatrix();
1252759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            }
1253a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
12547230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    }
1255a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1256a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy    /**
1257a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy     * Common Path information for clip path and normal path.
1258a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy     */
1259a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy    private static class VPath {
1260a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        protected PathParser.PathDataNode[] mNodes = null;
1261a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        String mPathName;
1262759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        int mChangingConfigurations;
1263a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1264a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public VPath() {
1265759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            // Empty constructor.
12668d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy        }
12678d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy
12688d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy        public VPath(VPath copy) {
12698d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mPathName = copy.mPathName;
12708d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mChangingConfigurations = copy.mChangingConfigurations;
12718d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            mNodes = PathParser.deepCopyNodes(copy.mNodes);
12728d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy        }
12738d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy
12748d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy        public void toPath(Path path) {
12758d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            path.reset();
12768d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy            if (mNodes != null) {
1277759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy                PathParser.PathDataNode.nodesToPath(mNodes, path);
1278a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            }
1279a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
1280a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1281a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public String getPathName() {
1282a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            return mPathName;
1283a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
1284a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1285a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public boolean canApplyTheme() {
1286a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            return false;
1287a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
1288a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1289a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public void applyTheme(Theme t) {
1290a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
1291a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1292a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public boolean isClipPath() {
1293a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            return false;
1294a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
1295a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy
1296a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
1297a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        @SuppressWarnings("unused")
1298a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        public PathParser.PathDataNode[] getPathData() {
1299a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            return mNodes;
1300a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
13017230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13027230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        @SuppressWarnings("unused")
13037230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        public void setPathData(PathParser.PathDataNode[] nodes) {
13047230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            if (!PathParser.canMorph(mNodes, nodes)) {
13057230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy                // This should not happen in the middle of animation.
13067230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy                mNodes = PathParser.deepCopyNodes(nodes);
13077230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            } else {
13087230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy                PathParser.updateNodes(mNodes, nodes);
13097230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            }
13107230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        }
13117230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    }
13127230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13137230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    /**
13147230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy     * Clip path, which only has name and pathData.
13157230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy     */
13167230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy    private static class VClipPath extends VPath {
13177230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        public VClipPath() {
13187230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            // Empty constructor.
13197230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        }
13207230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13217230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        public VClipPath(VClipPath copy) {
1322a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            super(copy);
1323a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
13247230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13257230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
13267230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            final TypedArray a = obtainAttributes(r, theme, attrs,
13277230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy                    R.styleable.VectorDrawableClipPath);
1328a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            updateStateFromTypedArray(a);
1329a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            a.recycle();
1330a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy        }
13317230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13327230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        private void updateStateFromTypedArray(TypedArray a) {
13337230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            // Account for any configuration changes.
13347230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            mChangingConfigurations |= a.getChangingConfigurations();
13357230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13367230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
13377230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            if (pathName != null) {
13387230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy                mPathName = pathName;
13397230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            }
13407230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13417230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
13427230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            if (pathData != null) {
13437230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy                mNodes = PathParser.createNodesFromPathData(pathData);
1344a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy            }
13458d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy        }
13467230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy
13477230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        @Override
13487230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy        public boolean isClipPath() {
13497230a74e9a36dfc6c4346c14e325bf07cd05b380Romain Guy            return true;
135029d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy        }
1351759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    }
1352759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
135385bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    /**
1354e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy     * Normal path, which contains all the fill / paint information.
1355af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy     */
1356e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    private static class VFullPath extends VPath {
1357ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy        /////////////////////////////////////////////////////
1358ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy        // Variables below need to be copied (deep copy if applicable) for mutation.
135970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy        private int[] mThemeAttrs;
13603d58c03de0d8877b36cdb78b0ca8b5cac7f600e2Romain Guy
1361c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        int mStrokeColor = Color.TRANSPARENT;
13629d5316e3f56d138504565ff311145ac01621dff4Romain Guy        float mStrokeWidth = 0;
1363c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
136401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        int mFillColor = Color.TRANSPARENT;
136501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        float mStrokeAlpha = 1.0f;
136601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        int mFillRule;
136701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        float mFillAlpha = 1.0f;
136801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        float mTrimPathStart = 0;
136901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        float mTrimPathEnd = 1;
137001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        float mTrimPathOffset = 0;
137101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
137201d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
1373c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
1374c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        float mStrokeMiterlimit = 4;
137501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
137601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        public VFullPath() {
137701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            // Empty constructor.
1378c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        }
1379c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
1380c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        public VFullPath(VFullPath copy) {
1381c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            super(copy);
138201d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            mThemeAttrs = copy.mThemeAttrs;
1383c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
1384c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mStrokeColor = copy.mStrokeColor;
1385c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mStrokeWidth = copy.mStrokeWidth;
1386c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mStrokeAlpha = copy.mStrokeAlpha;
138701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            mFillColor = copy.mFillColor;
1388c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mFillRule = copy.mFillRule;
1389c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mFillAlpha = copy.mFillAlpha;
139001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            mTrimPathStart = copy.mTrimPathStart;
1391c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mTrimPathEnd = copy.mTrimPathEnd;
1392c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mTrimPathOffset = copy.mTrimPathOffset;
139301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
1394c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mStrokeLineCap = copy.mStrokeLineCap;
1395c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mStrokeLineJoin = copy.mStrokeLineJoin;
1396c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            mStrokeMiterlimit = copy.mStrokeMiterlimit;
1397c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        }
1398c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
13998b2f5267f16c295f12faab810527cd6311997e34Romain Guy        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
14008b2f5267f16c295f12faab810527cd6311997e34Romain Guy            switch (id) {
14018b2f5267f16c295f12faab810527cd6311997e34Romain Guy                case LINECAP_BUTT:
14028b2f5267f16c295f12faab810527cd6311997e34Romain Guy                    return Paint.Cap.BUTT;
14038b2f5267f16c295f12faab810527cd6311997e34Romain Guy                case LINECAP_ROUND:
14048b2f5267f16c295f12faab810527cd6311997e34Romain Guy                    return Paint.Cap.ROUND;
14058b2f5267f16c295f12faab810527cd6311997e34Romain Guy                case LINECAP_SQUARE:
14068b2f5267f16c295f12faab810527cd6311997e34Romain Guy                    return Paint.Cap.SQUARE;
14078b2f5267f16c295f12faab810527cd6311997e34Romain Guy                default:
14088b2f5267f16c295f12faab810527cd6311997e34Romain Guy                    return defValue;
14098b2f5267f16c295f12faab810527cd6311997e34Romain Guy            }
14108b2f5267f16c295f12faab810527cd6311997e34Romain Guy        }
14118b2f5267f16c295f12faab810527cd6311997e34Romain Guy
14128b2f5267f16c295f12faab810527cd6311997e34Romain Guy        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
14138b2f5267f16c295f12faab810527cd6311997e34Romain Guy            switch (id) {
1414c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                case LINEJOIN_MITER:
1415c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                    return Paint.Join.MITER;
1416c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                case LINEJOIN_ROUND:
1417c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                    return Paint.Join.ROUND;
1418c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                case LINEJOIN_BEVEL:
1419c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                    return Paint.Join.BEVEL;
1420c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy                default:
142101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy                    return defValue;
142201d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            }
14235c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        }
1424c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
1425c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        @Override
1426c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        public boolean canApplyTheme() {
1427c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy            return mThemeAttrs != null;
1428c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy        }
14296926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
14306926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        public void inflate(Resources r, AttributeSet attrs, Theme theme) {
14316926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy            final TypedArray a = obtainAttributes(r, theme, attrs,
14326926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy                    R.styleable.VectorDrawablePath);
1433026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy            updateStateFromTypedArray(a);
1434746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy            a.recycle();
1435a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        }
1436a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
1437a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        private void updateStateFromTypedArray(TypedArray a) {
1438a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            // Account for any configuration changes.
1439a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            mChangingConfigurations |= a.getChangingConfigurations();
1440a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
1441a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            // Extract the theme attributes, if any.
1442026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy            mThemeAttrs = a.extractThemeAttrs();
1443026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
1444026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy            final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
1445026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy            if (pathName != null) {
1446026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy                mPathName = pathName;
1447d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy            }
1448026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
1449026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy            final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
1450026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy            if (pathData != null) {
1451026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy                mNodes = PathParser.createNodesFromPathData(pathData);
1452c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            }
14539d5316e3f56d138504565ff311145ac01621dff4Romain Guy
1454e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
1455e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    mFillColor);
1456b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy            mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha,
1457e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    mFillAlpha);
1458e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mStrokeLineCap = getStrokeLineCap(a.getInt(
1459af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
1460e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
1461f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
1462e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mStrokeMiterlimit = a.getFloat(
1463a674ab74e359ac73b4c4dd6b1a3a771836ac7e40Romain Guy                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
1464e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
1465e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    mStrokeColor);
1466e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
1467e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    mStrokeAlpha);
1468e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
1469e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    mStrokeWidth);
1470e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
1471e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    mTrimPathEnd);
1472e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mTrimPathOffset = a.getFloat(
1473e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
1474e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            mTrimPathStart = a.getFloat(
1475e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
1476e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        }
14776620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
14783a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy        @Override
14793a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy        public void applyTheme(Theme t) {
14806620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            if (mThemeAttrs == null) {
14816620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                return;
14826620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            }
14836620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
14846620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
14856620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            updateStateFromTypedArray(a);
1486b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy            a.recycle();
1487b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy        }
1488fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
1489e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
149086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
149186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        int getStrokeColor() {
149286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            return mStrokeColor;
14939d13fe25f4f10b25776b1dc5c858f9ebb0b28b30Romain Guy        }
14941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1495b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy        @SuppressWarnings("unused")
1496fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        void setStrokeColor(int strokeColor) {
14971e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            mStrokeColor = strokeColor;
14981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
14990a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
150086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
150186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        float getStrokeWidth() {
150286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            return mStrokeWidth;
150386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
150486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
150586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
150686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        void setStrokeWidth(float strokeWidth) {
150786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            mStrokeWidth = strokeWidth;
150886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
150986568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
151086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
151186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        float getStrokeAlpha() {
151286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            return mStrokeAlpha;
151386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
151486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
15150a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        @SuppressWarnings("unused")
15160a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        void setStrokeAlpha(float strokeAlpha) {
151786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            mStrokeAlpha = strokeAlpha;
15181e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
15191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1520b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy        @SuppressWarnings("unused")
1521b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy        int getFillColor() {
1522b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy            return mFillColor;
1523b146b1214ef6e4fc75d98779b22434335764cfdbRomain Guy        }
15246620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
15256620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
15266620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        void setFillColor(int fillColor) {
15276620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy            mFillColor = fillColor;
15286620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
15295b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
153086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
153186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        float getFillAlpha() {
153286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            return mFillAlpha;
153386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
153486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
153586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
153686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        void setFillAlpha(float fillAlpha) {
153786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            mFillAlpha = fillAlpha;
153886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
153986568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
154086568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        @SuppressWarnings("unused")
154186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        float getTrimPathStart() {
154286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy            return mTrimPathStart;
154386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy        }
154406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
15456620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
15465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        void setTrimPathStart(float trimPathStart) {
15475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            mTrimPathStart = trimPathStart;
15485b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
1549f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy
15505b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        @SuppressWarnings("unused")
1551f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy        float getTrimPathEnd() {
15525b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            return mTrimPathEnd;
15539d13fe25f4f10b25776b1dc5c858f9ebb0b28b30Romain Guy        }
155403750a067e818ca7fbd0f590e2ff6a8fded21e6cRomain Guy
15556620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
1556f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy        void setTrimPathEnd(float trimPathEnd) {
15575b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            mTrimPathEnd = trimPathEnd;
1558f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy        }
15596620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
15606620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        @SuppressWarnings("unused")
15616620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        float getTrimPathOffset() {
1562f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy            return mTrimPathOffset;
15635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
15645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
15655b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        @SuppressWarnings("unused")
1566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        void setTrimPathOffset(float trimPathOffset) {
1567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mTrimPathOffset = trimPathOffset;
1568fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
1569a674ab74e359ac73b4c4dd6b1a3a771836ac7e40Romain Guy    }
15703a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy}
1571694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy