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