VectorDrawable.java revision 16c1bd5db8f4f18e1eee8b19006bba5f06a88123
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) { 15016c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui if (theme != null && state.canApplyTheme()) { 15116c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui // If we need to apply a theme, implicitly mutate. 15216c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui mVectorState = new VectorDrawableState(state); 1539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette applyTheme(theme); 15416c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui } else { 15516c1bd5db8f4f18e1eee8b19006bba5f06a88123ztenghui mVectorState = state; 1569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 157b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 158b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 159b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mVectorState.mVPathRenderer.setColorFilter(mTintFilter); 160abb7d134c02ac60091108c491dafb00877093170John Hoford } 161abb7d134c02ac60091108c491dafb00877093170John Hoford 162e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Object getTargetByName(String name) { 163e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mVGTargetsMap.get(name); 164e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 165e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 166abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 167abb7d134c02ac60091108c491dafb00877093170John Hoford public ConstantState getConstantState() { 168abb7d134c02ac60091108c491dafb00877093170John Hoford return mVectorState; 169abb7d134c02ac60091108c491dafb00877093170John Hoford } 170abb7d134c02ac60091108c491dafb00877093170John Hoford 1714554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette @Override 172abb7d134c02ac60091108c491dafb00877093170John Hoford public void draw(Canvas canvas) { 1734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final int saveCount = canvas.save(); 1744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Rect bounds = getBounds(); 1754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.translate(bounds.left, bounds.top); 176ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); 1774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.restoreToCount(saveCount); 178abb7d134c02ac60091108c491dafb00877093170John Hoford } 179abb7d134c02ac60091108c491dafb00877093170John Hoford 180abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 181e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public int getAlpha() { 182e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mVectorState.mVPathRenderer.getRootAlpha(); 183e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 184e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 185e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui @Override 186abb7d134c02ac60091108c491dafb00877093170John Hoford public void setAlpha(int alpha) { 1872af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) { 1882af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mVectorState.mVPathRenderer.setRootAlpha(alpha); 189abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 190abb7d134c02ac60091108c491dafb00877093170John Hoford } 191abb7d134c02ac60091108c491dafb00877093170John Hoford } 192abb7d134c02ac60091108c491dafb00877093170John Hoford 193abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 194abb7d134c02ac60091108c491dafb00877093170John Hoford public void setColorFilter(ColorFilter colorFilter) { 195b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette final VectorDrawableState state = mVectorState; 196b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette if (colorFilter != null) { 197b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette // Color filter overrides tint. 198b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTintFilter = null; 199b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette } else if (state.mTint != null && state.mTintMode != null) { 200b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette // Restore the tint filter, if we need one. 201b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT); 202b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); 203b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette colorFilter = mTintFilter; 204b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette } 205b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 206b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette state.mVPathRenderer.setColorFilter(colorFilter); 207fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette invalidateSelf(); 208abb7d134c02ac60091108c491dafb00877093170John Hoford } 209abb7d134c02ac60091108c491dafb00877093170John Hoford 210abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 211b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette public void setTint(ColorStateList tint, Mode tintMode) { 212b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette final VectorDrawableState state = mVectorState; 213b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette if (state.mTint != tint || state.mTintMode != tintMode) { 214b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette state.mTint = tint; 215b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette state.mTintMode = tintMode; 216b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 217b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); 218b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mVectorState.mVPathRenderer.setColorFilter(mTintFilter); 219b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette invalidateSelf(); 220b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette } 221b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette } 222b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 223b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette @Override 224b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette protected boolean onStateChange(int[] stateSet) { 225b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette final VectorDrawableState state = mVectorState; 226b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette if (state.mTint != null && state.mTintMode != null) { 227b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 228b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mVectorState.mVPathRenderer.setColorFilter(mTintFilter); 229b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette return true; 230b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette } 231b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette return false; 232b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette } 233b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 234b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette @Override 235abb7d134c02ac60091108c491dafb00877093170John Hoford public int getOpacity() { 236abb7d134c02ac60091108c491dafb00877093170John Hoford return PixelFormat.TRANSLUCENT; 237abb7d134c02ac60091108c491dafb00877093170John Hoford } 238abb7d134c02ac60091108c491dafb00877093170John Hoford 239abb7d134c02ac60091108c491dafb00877093170John Hoford /** 240d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * Sets padding for this shape, defined by a Rect object. Define the padding 241d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * in the Rect object as: left, top, right, bottom. 242abb7d134c02ac60091108c491dafb00877093170John Hoford */ 243abb7d134c02ac60091108c491dafb00877093170John Hoford public void setPadding(Rect padding) { 244abb7d134c02ac60091108c491dafb00877093170John Hoford setPadding(padding.left, padding.top, padding.right, padding.bottom); 245abb7d134c02ac60091108c491dafb00877093170John Hoford } 246abb7d134c02ac60091108c491dafb00877093170John Hoford 247abb7d134c02ac60091108c491dafb00877093170John Hoford /** 248abb7d134c02ac60091108c491dafb00877093170John Hoford * Sets padding for the shape. 249abb7d134c02ac60091108c491dafb00877093170John Hoford * 250abb7d134c02ac60091108c491dafb00877093170John Hoford * @param left padding for the left side (in pixels) 251abb7d134c02ac60091108c491dafb00877093170John Hoford * @param top padding for the top (in pixels) 252abb7d134c02ac60091108c491dafb00877093170John Hoford * @param right padding for the right side (in pixels) 253abb7d134c02ac60091108c491dafb00877093170John Hoford * @param bottom padding for the bottom (in pixels) 254abb7d134c02ac60091108c491dafb00877093170John Hoford */ 255abb7d134c02ac60091108c491dafb00877093170John Hoford public void setPadding(int left, int top, int right, int bottom) { 256abb7d134c02ac60091108c491dafb00877093170John Hoford if ((left | top | right | bottom) == 0) { 257abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding = null; 258abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 259abb7d134c02ac60091108c491dafb00877093170John Hoford if (mVectorState.mPadding == null) { 260abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding = new Rect(); 261abb7d134c02ac60091108c491dafb00877093170John Hoford } 262abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding.set(left, top, right, bottom); 263abb7d134c02ac60091108c491dafb00877093170John Hoford } 264abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 265abb7d134c02ac60091108c491dafb00877093170John Hoford } 266abb7d134c02ac60091108c491dafb00877093170John Hoford 267abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 268abb7d134c02ac60091108c491dafb00877093170John Hoford public int getIntrinsicWidth() { 269ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return (int) mVectorState.mVPathRenderer.mBaseWidth; 270abb7d134c02ac60091108c491dafb00877093170John Hoford } 271abb7d134c02ac60091108c491dafb00877093170John Hoford 272abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 273abb7d134c02ac60091108c491dafb00877093170John Hoford public int getIntrinsicHeight() { 274ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return (int) mVectorState.mVPathRenderer.mBaseHeight; 275abb7d134c02ac60091108c491dafb00877093170John Hoford } 276abb7d134c02ac60091108c491dafb00877093170John Hoford 277abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 278abb7d134c02ac60091108c491dafb00877093170John Hoford public boolean getPadding(Rect padding) { 279abb7d134c02ac60091108c491dafb00877093170John Hoford if (mVectorState.mPadding != null) { 280abb7d134c02ac60091108c491dafb00877093170John Hoford padding.set(mVectorState.mPadding); 281abb7d134c02ac60091108c491dafb00877093170John Hoford return true; 282abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 283abb7d134c02ac60091108c491dafb00877093170John Hoford return super.getPadding(padding); 284abb7d134c02ac60091108c491dafb00877093170John Hoford } 285abb7d134c02ac60091108c491dafb00877093170John Hoford } 286abb7d134c02ac60091108c491dafb00877093170John Hoford 287abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 288abb7d134c02ac60091108c491dafb00877093170John Hoford public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) 289abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException, IOException { 290ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer p = inflateInternal(res, parser, attrs, theme); 291ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui setPathRenderer(p); 292abb7d134c02ac60091108c491dafb00877093170John Hoford } 293abb7d134c02ac60091108c491dafb00877093170John Hoford 2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette @Override 2959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 2969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme(); 2979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette @Override 3009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 3019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette super.applyTheme(t); 3029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VectorDrawableState state = mVectorState; 304ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer path = state.mVPathRenderer; 3059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (path != null && path.canApplyTheme()) { 3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.applyTheme(t); 3079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 3089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3104b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette /** @hide */ 3114b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette public static VectorDrawable create(Resources resources, int rid) { 3124b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette try { 3134b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final XmlPullParser xpp = resources.getXml(rid); 3144b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final AttributeSet attrs = Xml.asAttributeSet(xpp); 3154b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 3164b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette factory.setNamespaceAware(true); 3174b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 3184b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final VectorDrawable drawable = new VectorDrawable(); 3194b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette drawable.inflate(resources, xpp, attrs); 3204b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 3214b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette return drawable; 3224b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } catch (XmlPullParserException e) { 3234b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette Log.e(LOGTAG, "parser error", e); 3244b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } catch (IOException e) { 3254b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette Log.e(LOGTAG, "parser error", e); 3264b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } 3274b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette return null; 3284b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } 3294b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 3302af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui private static int applyAlpha(int color, float alpha) { 3312af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui int alphaBytes = Color.alpha(color); 3322af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui color &= 0x00FFFFFF; 3332af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui color |= ((int) (alphaBytes * alpha)) << 24; 3342af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui return color; 3352af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 3362af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui 337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, 3389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette Theme theme) throws XmlPullParserException, IOException { 339ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer pathRenderer = new VPathRenderer(); 3409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 341abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noSizeTag = true; 342abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noViewportTag = true; 3436d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui boolean noGroupTag = true; 344abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noPathTag = true; 3459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Use a stack to help to build the group tree. 3474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // The top of the stack is always the current group. 3484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final Stack<VGroup> groupStack = new Stack<VGroup>(); 3494d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui groupStack.push(pathRenderer.mRootGroup); 350abb7d134c02ac60091108c491dafb00877093170John Hoford 351abb7d134c02ac60091108c491dafb00877093170John Hoford int eventType = parser.getEventType(); 352abb7d134c02ac60091108c491dafb00877093170John Hoford while (eventType != XmlPullParser.END_DOCUMENT) { 353abb7d134c02ac60091108c491dafb00877093170John Hoford if (eventType == XmlPullParser.START_TAG) { 3549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final String tagName = parser.getName(); 3554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final VGroup currentGroup = groupStack.peek(); 3564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 357abb7d134c02ac60091108c491dafb00877093170John Hoford if (SHAPE_PATH.equals(tagName)) { 3589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VPath path = new VPath(); 3599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.inflate(res, attrs, theme); 3609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette currentGroup.add(path); 361e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (path.getPathName() != null) { 362e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mVGTargetsMap.put(path.getPathName(), path); 363e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 364abb7d134c02ac60091108c491dafb00877093170John Hoford noPathTag = false; 365abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_SIZE.equals(tagName)) { 366ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseSize(res, attrs); 367abb7d134c02ac60091108c491dafb00877093170John Hoford noSizeTag = false; 368abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_VIEWPORT.equals(tagName)) { 369ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseViewport(res, attrs); 370abb7d134c02ac60091108c491dafb00877093170John Hoford noViewportTag = false; 3716d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui } else if (SHAPE_GROUP.equals(tagName)) { 3724d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui VGroup newChildGroup = new VGroup(); 3734d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui newChildGroup.inflate(res, attrs, theme); 3744d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui currentGroup.mChildGroupList.add(newChildGroup); 3754d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui groupStack.push(newChildGroup); 376e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (newChildGroup.getGroupName() != null) { 377e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup); 378e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 3796d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui noGroupTag = false; 380abb7d134c02ac60091108c491dafb00877093170John Hoford } 3814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } else if (eventType == XmlPullParser.END_TAG) { 3824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final String tagName = parser.getName(); 3834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (SHAPE_GROUP.equals(tagName)) { 3844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui groupStack.pop(); 3854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 386abb7d134c02ac60091108c491dafb00877093170John Hoford } 387abb7d134c02ac60091108c491dafb00877093170John Hoford eventType = parser.next(); 388abb7d134c02ac60091108c491dafb00877093170John Hoford } 3899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3904d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Print the tree out for debug. 3914d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (DBG_VECTOR_DRAWABLE) { 3924d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui printGroupTree(pathRenderer.mRootGroup, 0); 3936d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui } 3946d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui 39546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui if (noSizeTag || noViewportTag || noPathTag) { 3969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final StringBuffer tag = new StringBuffer(); 3979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 398abb7d134c02ac60091108c491dafb00877093170John Hoford if (noSizeTag) { 3999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 400abb7d134c02ac60091108c491dafb00877093170John Hoford } 4019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 402d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noViewportTag) { 403d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 404abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" & "); 405abb7d134c02ac60091108c491dafb00877093170John Hoford } 4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 407abb7d134c02ac60091108c491dafb00877093170John Hoford } 4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 409d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noPathTag) { 410d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 411abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" or "); 412abb7d134c02ac60091108c491dafb00877093170John Hoford } 4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_PATH); 414abb7d134c02ac60091108c491dafb00877093170John Hoford } 4159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 4169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette throw new XmlPullParserException("no " + tag + " defined"); 417abb7d134c02ac60091108c491dafb00877093170John Hoford } 4189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 419ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return pathRenderer; 420abb7d134c02ac60091108c491dafb00877093170John Hoford } 421abb7d134c02ac60091108c491dafb00877093170John Hoford 4224d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private void printGroupTree(VGroup currentGroup, int level) { 4234d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui String indent = ""; 4244d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int i = 0 ; i < level ; i++) { 4254d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui indent += " "; 4264d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 4274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Print the current node 428e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName() 4294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui + " rotation is " + currentGroup.mRotate); 4304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString()); 4314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Then print all the children 4324d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) { 4334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui printGroupTree(currentGroup.mChildGroupList.get(i), level + 1); 4344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 4354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 4364d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 437ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private void setPathRenderer(VPathRenderer pathRenderer) { 438ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer = pathRenderer; 439abb7d134c02ac60091108c491dafb00877093170John Hoford } 440abb7d134c02ac60091108c491dafb00877093170John Hoford 4415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private static class VectorDrawableState extends ConstantState { 4425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette int mChangingConfigurations; 443ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui VPathRenderer mVPathRenderer; 4445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette Rect mPadding; 445b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette ColorStateList mTint; 446b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette Mode mTintMode; 4475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 4485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public VectorDrawableState(VectorDrawableState copy) { 4495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette if (copy != null) { 4505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mChangingConfigurations = copy.mChangingConfigurations; 4514d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // TODO: Make sure the constant state are handled correctly. 452ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); 4535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mPadding = new Rect(copy.mPadding); 454b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTint = copy.mTint; 455b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette mTintMode = copy.mTintMode; 4565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 4595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 4605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable() { 4615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, null, null); 4625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 4645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 4655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res) { 4665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, null); 4675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 4695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 4705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res, Theme theme) { 4715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, theme); 4725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 4745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 4755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public int getChangingConfigurations() { 4765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return mChangingConfigurations; 4775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 4795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 480ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private static class VPathRenderer { 4814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui /* Right now the internal data structure is organized as a tree. 4824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * Each node can be a group node, or a path. 4834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * A group node can have groups or paths as children, but a path node has 4844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * no children. 4854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * One example can be: 4864d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * Root Group 4874d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * / | \ 4884d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * Group Path Group 4894d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * / \ | 4904d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * Path Path Path 4914d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui * 4924d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui */ 4934d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private final VGroup mRootGroup; 4944d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 4954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mPath = new Path(); 4964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mRenderPath = new Path(); 4974d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private static final Matrix IDENTITY_MATRIX = new Matrix(); 4984b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 4994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mStrokePaint; 5004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mFillPaint; 501fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette private ColorFilter mColorFilter; 502abb7d134c02ac60091108c491dafb00877093170John Hoford private PathMeasure mPathMeasure; 5034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5044d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private float mBaseWidth = 0; 5054d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private float mBaseHeight = 0; 5064d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private float mViewportWidth = 0; 5074d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private float mViewportHeight = 0; 5082af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui private int mRootAlpha = 0xFF; 5099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 5104d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private final Matrix mFinalPathMatrix = new Matrix(); 511abb7d134c02ac60091108c491dafb00877093170John Hoford 512ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer() { 5134d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mRootGroup = new VGroup(); 514abb7d134c02ac60091108c491dafb00877093170John Hoford } 5159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 5162af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui public void setRootAlpha(int alpha) { 5172af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mRootAlpha = alpha; 5182af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 5192af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui 5202af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui public int getRootAlpha() { 5212af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui return mRootAlpha; 5222af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 5232af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui 524ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer(VPathRenderer copy) { 5254d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mRootGroup = copy.mRootGroup; 526abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseWidth = copy.mBaseWidth; 527abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseHeight = copy.mBaseHeight; 528abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportWidth = copy.mViewportHeight; 529abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportHeight = copy.mViewportHeight; 530abb7d134c02ac60091108c491dafb00877093170John Hoford } 531abb7d134c02ac60091108c491dafb00877093170John Hoford 5329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 5334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // If one of the paths can apply theme, then return true; 5344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui return recursiveCanApplyTheme(mRootGroup); 5354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 5364d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 5374d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private boolean recursiveCanApplyTheme(VGroup currentGroup) { 5384d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // We can do a tree traverse here, if there is one path return true, 5394d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // then we return true for the whole tree. 5404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final ArrayList<VPath> paths = currentGroup.mPathList; 5414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int j = paths.size() - 1; j >= 0; j--) { 5424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final VPath path = paths.get(j); 5434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (path.canApplyTheme()) { 5444d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui return true; 5459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 5469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 5476d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui 5484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList; 5494d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 5504d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int i = 0; i < childGroups.size(); i++) { 5514d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui VGroup childGroup = childGroups.get(i); 5524d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (childGroup.canApplyTheme() 5534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui || recursiveCanApplyTheme(childGroup)) { 5544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui return true; 5554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 5564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 5579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return false; 5589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 5599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 5609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 5614d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Apply theme to every path of the tree. 5624d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui recursiveApplyTheme(mRootGroup, t); 5634d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 5644d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 5654d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private void recursiveApplyTheme(VGroup currentGroup, Theme t) { 5664d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // We can do a tree traverse here, apply theme to all paths which 5674d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // can apply theme. 5684d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final ArrayList<VPath> paths = currentGroup.mPathList; 5694d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int j = paths.size() - 1; j >= 0; j--) { 5704d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final VPath path = paths.get(j); 5714d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (path.canApplyTheme()) { 5724d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui path.applyTheme(t); 5739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 5749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 5754d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 5764d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList; 5774d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 5784d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int i = 0; i < childGroups.size(); i++) { 5794d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui VGroup childGroup = childGroups.get(i); 5804d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (childGroup.canApplyTheme()) { 5814d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui childGroup.applyTheme(t); 5824d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 5834d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui recursiveApplyTheme(childGroup, t); 5844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 5854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 586abb7d134c02ac60091108c491dafb00877093170John Hoford } 587abb7d134c02ac60091108c491dafb00877093170John Hoford 588fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette public void setColorFilter(ColorFilter colorFilter) { 589fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mColorFilter = colorFilter; 590fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 591fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mFillPaint != null) { 592fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mFillPaint.setColorFilter(colorFilter); 593fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } 594fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 595fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mStrokePaint != null) { 596fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mStrokePaint.setColorFilter(colorFilter); 597fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } 5986d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui 599fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } 600fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 6014d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix, 6022af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui float currentAlpha, Canvas canvas, int w, int h) { 6034d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Calculate current group's matrix by preConcat the parent's and 6044d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // and the current one on the top of the stack. 6054d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Basically the Mfinal = Mviewport * M0 * M1 * M2; 6064d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Mi the local matrix at level i of the group tree. 6074d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui currentGroup.mStackedMatrix.set(currentMatrix); 6084d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 6094d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix); 6104d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 6112af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui float stackedAlpha = currentAlpha * currentGroup.mGroupAlpha; 6122af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui drawPath(currentGroup, stackedAlpha, canvas, w, h); 6134d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Draw the group tree in post order. 6144d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) { 6154d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui drawGroupTree(currentGroup.mChildGroupList.get(i), 6162af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui currentGroup.mStackedMatrix, stackedAlpha, canvas, w, h); 617abb7d134c02ac60091108c491dafb00877093170John Hoford } 6184d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 619abb7d134c02ac60091108c491dafb00877093170John Hoford 6204d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui public void draw(Canvas canvas, int w, int h) { 6214d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // Travese the tree in pre-order to draw. 6222af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h); 623abb7d134c02ac60091108c491dafb00877093170John Hoford } 624abb7d134c02ac60091108c491dafb00877093170John Hoford 6252af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui private void drawPath(VGroup vGroup, float stackedAlpha, Canvas canvas, int w, int h) { 6269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final float scale = Math.min(h / mViewportHeight, w / mViewportWidth); 627abb7d134c02ac60091108c491dafb00877093170John Hoford 6284d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mFinalPathMatrix.set(vGroup.mStackedMatrix); 6294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mFinalPathMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f); 6304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mFinalPathMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f); 631abb7d134c02ac60091108c491dafb00877093170John Hoford 63263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui ArrayList<VPath> paths = vGroup.getPaths(); 63363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui for (int i = 0; i < paths.size(); i++) { 63463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui VPath vPath = paths.get(i); 63563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui vPath.toPath(mPath); 63663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final Path path = mPath; 637abb7d134c02ac60091108c491dafb00877093170John Hoford 63863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { 63963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; 64063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f; 6419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 64263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mPathMeasure == null) { 64363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure = new PathMeasure(); 64463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 64563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.setPath(mPath, false); 64663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 64763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui float len = mPathMeasure.getLength(); 64863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui start = start * len; 64963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui end = end * len; 65063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui path.reset(); 65163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (start > end) { 65263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.getSegment(start, len, path, true); 65363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.getSegment(0f, end, path, true); 65463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } else { 65563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.getSegment(start, end, path, true); 65663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 65763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui path.rLineTo(0, 0); // fix bug in measure 6584b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette } 6594b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 66063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRenderPath.reset(); 6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6624d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mRenderPath.addPath(path, mFinalPathMatrix); 6634b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 66463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mClip) { 66563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui canvas.clipPath(mRenderPath, Region.Op.REPLACE); 6662af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } else { 6672af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (vPath.mFillColor != 0) { 6682af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (mFillPaint == null) { 6692af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mFillPaint = new Paint(); 6702af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mFillPaint.setColorFilter(mColorFilter); 6712af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mFillPaint.setStyle(Paint.Style.FILL); 6722af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mFillPaint.setAntiAlias(true); 6732af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 6742af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha)); 6752af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui canvas.drawPath(mRenderPath, mFillPaint); 67663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 67763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 6782af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (vPath.mStrokeColor != 0) { 6792af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (mStrokePaint == null) { 6802af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mStrokePaint = new Paint(); 6812af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mStrokePaint.setColorFilter(mColorFilter); 6822af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mStrokePaint.setStyle(Paint.Style.STROKE); 6832af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mStrokePaint.setAntiAlias(true); 6842af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 6854b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 6862af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui final Paint strokePaint = mStrokePaint; 6872af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (vPath.mStrokeLineJoin != null) { 6882af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); 6892af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 690abb7d134c02ac60091108c491dafb00877093170John Hoford 6912af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui if (vPath.mStrokeLineCap != null) { 6922af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui strokePaint.setStrokeCap(vPath.mStrokeLineCap); 6932af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 69463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 6952af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); 69663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 6972af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha)); 6982af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); 6992af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui canvas.drawPath(mRenderPath, strokePaint); 7002af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui } 70163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 702abb7d134c02ac60091108c491dafb00877093170John Hoford } 703abb7d134c02ac60091108c491dafb00877093170John Hoford } 704abb7d134c02ac60091108c491dafb00877093170John Hoford 705abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseViewport(Resources r, AttributeSet attrs) 706abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 7074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); 708fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth); 709fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight); 710fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 711fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mViewportWidth <= 0) { 712fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 713fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<viewport> tag requires viewportWidth > 0"); 714fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } else if (mViewportHeight <= 0) { 715fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 716fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<viewport> tag requires viewportHeight > 0"); 717abb7d134c02ac60091108c491dafb00877093170John Hoford } 718fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 719abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 720abb7d134c02ac60091108c491dafb00877093170John Hoford } 721abb7d134c02ac60091108c491dafb00877093170John Hoford 722abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseSize(Resources r, AttributeSet attrs) 723abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 7244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); 725fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth); 726fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight); 727fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 728fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mBaseWidth <= 0) { 729fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 730fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<size> tag requires width > 0"); 731fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } else if (mBaseHeight <= 0) { 732fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 733fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<size> tag requires height > 0"); 734abb7d134c02ac60091108c491dafb00877093170John Hoford } 735fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 736abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 737abb7d134c02ac60091108c491dafb00877093170John Hoford } 7384b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 739abb7d134c02ac60091108c491dafb00877093170John Hoford } 740abb7d134c02ac60091108c491dafb00877093170John Hoford 741e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui static class VGroup { 7424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private final ArrayList<VPath> mPathList = new ArrayList<VPath>(); 7434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>(); 744abb7d134c02ac60091108c491dafb00877093170John Hoford 74563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private float mRotate = 0; 74663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private float mPivotX = 0; 74763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private float mPivotY = 0; 748452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui private float mScaleX = 1; 749452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui private float mScaleY = 1; 750452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui private float mTranslateX = 0; 751452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui private float mTranslateY = 0; 7522af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui private float mGroupAlpha = 1; 7534d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 7544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // mLocalMatrix is parsed from the XML. 7554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private final Matrix mLocalMatrix = new Matrix(); 7564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // mStackedMatrix is only used when drawing, it combines all the 7574d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // parents' local matrices with the current one. 7584d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private final Matrix mStackedMatrix = new Matrix(); 75963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 76063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private int[] mThemeAttrs; 76163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 762e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private String mGroupName = null; 763e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 764e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /* Getter and Setter */ 765e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getRotation() { 766e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mRotate; 767e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 768e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 769e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setRotation(float rotation) { 770e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (rotation != mRotate) { 771e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mRotate = rotation; 772e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 773e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 774e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 775e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 776e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getPivotX() { 777e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mPivotX; 778e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 779e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 780e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setPivotX(float pivotX) { 781e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (pivotX != mPivotX) { 782e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mPivotX = pivotX; 783e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 784e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 785e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 786e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 787e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getPivotY() { 788e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mPivotY; 789e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 790e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 791e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setPivotY(float pivotY) { 792e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (pivotY != mPivotY) { 793e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mPivotY = pivotY; 794e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 795e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 796e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 797e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 798e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getScaleX() { 799e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mScaleX; 800e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 8014d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 802e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setScaleX(float scaleX) { 803e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (scaleX != mScaleX) { 804e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mScaleX = scaleX; 805e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 806e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 807e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 808e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 809e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getScaleY() { 810e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mScaleY; 811e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 812e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 813e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setScaleY(float scaleY) { 814e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (scaleY != mScaleY) { 815e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mScaleY = scaleY; 816e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 817e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 818e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 819e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 820e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getTranslateX() { 821e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mTranslateX; 822e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 823e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 824e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setTranslateX(float translateX) { 825e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (translateX != mTranslateX) { 826e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mTranslateX = translateX; 827e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 828e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 829e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 830e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 831e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getTranslateY() { 832e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mTranslateY; 833e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 834e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 835e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setTranslateY(float translateY) { 836e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (translateY != mTranslateY) { 837e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mTranslateY = translateY; 838e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui updateLocalMatrix(); 839e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 840e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 841e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 842e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public float getAlpha() { 843e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mGroupAlpha; 844e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 845e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 846e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public void setAlpha(float groupAlpha) { 847e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui if (groupAlpha != mGroupAlpha) { 848e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mGroupAlpha = groupAlpha; 849e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 850e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 851e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 852e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public String getGroupName() { 853e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mGroupName; 8544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 8554d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 8564d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui public Matrix getLocalMatrix() { 8574d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui return mLocalMatrix; 8584d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 8594d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 860abb7d134c02ac60091108c491dafb00877093170John Hoford public void add(VPath path) { 8614d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mPathList.add(path); 862abb7d134c02ac60091108c491dafb00877093170John Hoford } 863abb7d134c02ac60091108c491dafb00877093170John Hoford 8644d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui public boolean canApplyTheme() { 8654d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui return mThemeAttrs != null; 8664d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 8674d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 86863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui public void applyTheme(Theme t) { 86963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mThemeAttrs == null) { 87063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui return; 87163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 87263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 87363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final TypedArray a = t.resolveAttributes( 87463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mThemeAttrs, R.styleable.VectorDrawablePath); 87563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 87663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); 87763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); 87863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); 879452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX); 880452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY); 881452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX); 882452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY); 8832af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha); 8844d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui updateLocalMatrix(); 8854d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (a.hasValue(R.styleable.VectorDrawableGroup_name)) { 886e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mGroupName = a.getString(R.styleable.VectorDrawableGroup_name); 8874d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 88863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui a.recycle(); 88963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 89063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 89163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui public void inflate(Resources res, AttributeSet attrs, Theme theme) { 89263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup); 89363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final int[] themeAttrs = a.extractThemeAttrs(); 89463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 89563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mThemeAttrs = themeAttrs; 89663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui // NOTE: The set of attributes loaded here MUST match the 89763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui // set of attributes loaded in applyTheme. 89863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 89963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) { 90063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); 90163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 90263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 90363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) { 90463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); 90563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 90663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 90763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) { 90863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); 90963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 91063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 911452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleX] == 0) { 912452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX); 913452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui } 914452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui 915452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleY] == 0) { 916452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY); 917452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui } 918452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui 919452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateX] == 0) { 920452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX); 921452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui } 922452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui 923452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateY] == 0) { 924452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY); 925452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui } 926452f6ece7fe2fd1a85fca53f54e90bf041083b21ztenghui 9274d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) { 928e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mGroupName = a.getString(R.styleable.VectorDrawableGroup_name); 9294d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 9304d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 9314d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) { 9322af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha); 9334d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 9344d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 9354d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui updateLocalMatrix(); 93663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui a.recycle(); 93763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 93863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 9394d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui private void updateLocalMatrix() { 9404d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // The order we apply is the same as the 9414d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui // RenderNode.cpp::applyViewPropertyTransforms(). 9424d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mLocalMatrix.reset(); 9434d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mLocalMatrix.postTranslate(-mPivotX, -mPivotY); 9444d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mLocalMatrix.postScale(mScaleX, mScaleY); 9454d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mLocalMatrix.postRotate(mRotate, 0, 0); 9464d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); 9474d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui } 9484d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui 949abb7d134c02ac60091108c491dafb00877093170John Hoford /** 950abb7d134c02ac60091108c491dafb00877093170John Hoford * Must return in order of adding 951abb7d134c02ac60091108c491dafb00877093170John Hoford * @return ordered list of paths 952abb7d134c02ac60091108c491dafb00877093170John Hoford */ 95363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui public ArrayList<VPath> getPaths() { 9544d24caf1dec2babf273b18c99638fe2a0635ced4ztenghui return mPathList; 955abb7d134c02ac60091108c491dafb00877093170John Hoford } 956abb7d134c02ac60091108c491dafb00877093170John Hoford 957abb7d134c02ac60091108c491dafb00877093170John Hoford } 958abb7d134c02ac60091108c491dafb00877093170John Hoford 959e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui static class VPath { 9609453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private int[] mThemeAttrs; 9619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 962abb7d134c02ac60091108c491dafb00877093170John Hoford int mStrokeColor = 0; 963abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeWidth = 0; 964abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeOpacity = Float.NaN; 9652af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui int mFillColor = Color.BLACK; 966abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillRule; 967abb7d134c02ac60091108c491dafb00877093170John Hoford float mFillOpacity = Float.NaN; 968abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathStart = 0; 969abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathEnd = 1; 970abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathOffset = 0; 9719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 972abb7d134c02ac60091108c491dafb00877093170John Hoford boolean mClip = false; 9734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; 9744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Join mStrokeLineJoin = Paint.Join.MITER; 975abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeMiterlimit = 4; 9769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 9779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VNode[] mNode = null; 978e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui private String mPathName; 979abb7d134c02ac60091108c491dafb00877093170John Hoford 9809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public VPath() { 9819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette // Empty constructor. 9829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 9839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 984abb7d134c02ac60091108c491dafb00877093170John Hoford public void toPath(Path path) { 985abb7d134c02ac60091108c491dafb00877093170John Hoford path.reset(); 986abb7d134c02ac60091108c491dafb00877093170John Hoford if (mNode != null) { 987abb7d134c02ac60091108c491dafb00877093170John Hoford VNode.createPath(mNode, path); 988abb7d134c02ac60091108c491dafb00877093170John Hoford } 989abb7d134c02ac60091108c491dafb00877093170John Hoford } 990abb7d134c02ac60091108c491dafb00877093170John Hoford 991e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui public String getPathName() { 992e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mPathName; 993abb7d134c02ac60091108c491dafb00877093170John Hoford } 994abb7d134c02ac60091108c491dafb00877093170John Hoford 9957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { 9967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 9977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_BUTT: 9987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.BUTT; 9997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_ROUND: 10007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.ROUND; 10017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_SQUARE: 10027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.SQUARE; 10037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 10047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 10057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 10067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 10077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 10087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) { 10097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 10107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_MITER: 10117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.MITER; 10127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_ROUND: 10137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.ROUND; 10147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_BEVEL: 10157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.BEVEL; 10167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 10177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 10187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 10197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 10207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 1021e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui /* Setters and Getters */ 1022e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int getStroke() { 1023e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mStrokeColor; 1024e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1025e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1026e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setStroke(int strokeColor) { 1027e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mStrokeColor = strokeColor; 1028e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1029e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1030e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui float getStrokeWidth() { 1031e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mStrokeWidth; 1032e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1033e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1034e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setStrokeWidth(float strokeWidth) { 1035e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mStrokeWidth = strokeWidth; 1036e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1037e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1038e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui float getStrokeOpacity() { 1039e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mStrokeOpacity; 1040e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1041e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1042e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setStrokeOpacity(float strokeOpacity) { 1043e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mStrokeOpacity = strokeOpacity; 1044e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1045e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1046e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui int getFill() { 1047e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mFillColor; 1048e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1049e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1050e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setFill(int fillColor) { 1051e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mFillColor = fillColor; 1052e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1053e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1054e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui float getFillOpacity() { 1055e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mFillOpacity; 1056e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1057e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1058e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setFillOpacity(float fillOpacity) { 1059e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mFillOpacity = fillOpacity; 1060e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1061e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1062e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui float getTrimPathStart() { 1063e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mTrimPathStart; 1064e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1065e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1066e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setTrimPathStart(float trimPathStart) { 1067e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mTrimPathStart = trimPathStart; 1068e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1069e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1070e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui float getTrimPathEnd() { 1071e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mTrimPathEnd; 1072e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1073e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1074e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setTrimPathEnd(float trimPathEnd) { 1075e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mTrimPathEnd = trimPathEnd; 1076e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1077e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1078e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui float getTrimPathOffset() { 1079e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui return mTrimPathOffset; 1080e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1081e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 1082e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui void setTrimPathOffset(float trimPathOffset) { 1083e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mTrimPathOffset = trimPathOffset; 1084e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui } 1085e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui 10869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void inflate(Resources r, AttributeSet attrs, Theme theme) { 10879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath); 10889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final int[] themeAttrs = a.extractThemeAttrs(); 10899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mThemeAttrs = themeAttrs; 10909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 10917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // NOTE: The set of attributes loaded here MUST match the 10927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // set of attributes loaded in applyTheme. 10937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) { 10947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 10957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 10967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 10977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) { 1098e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mPathName = a.getString(R.styleable.VectorDrawablePath_name); 10997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 11017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) { 11027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 11037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 1104abb7d134c02ac60091108c491dafb00877093170John Hoford 11059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) { 11067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 11079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 11089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) { 11107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 1111abb7d134c02ac60091108c491dafb00877093170John Hoford } 11129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 11147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) { 11157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap( 11167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 11177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 11197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 11207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) { 11217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin( 11227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 1123abb7d134c02ac60091108c491dafb00877093170John Hoford } 11249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 11267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) { 11277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 11287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 11297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) { 11329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 1133abb7d134c02ac60091108c491dafb00877093170John Hoford } 11349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null 11369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) { 11379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeOpacity = a.getFloat( 11387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 11399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 11409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) { 11427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 11437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 11457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) { 11467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 11477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 11507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) { 11517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 11527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 11537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 11557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 11567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) { 11577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 11587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 11597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 11607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 11619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 11629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1163abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 1164abb7d134c02ac60091108c491dafb00877093170John Hoford } 1165abb7d134c02ac60091108c491dafb00877093170John Hoford 11669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 11679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return mThemeAttrs != null; 11689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 11699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 11719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (mThemeAttrs == null) { 11729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return; 11739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 11749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = t.resolveAttributes( 11760cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette mThemeAttrs, R.styleable.VectorDrawablePath); 11779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 11799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_name)) { 1181e5e92602a41a4ddc7b42cd1c171a0edfbd09b8daztenghui mPathName = a.getString(R.styleable.VectorDrawablePath_name); 11829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 11839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) { 11857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 11869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 11879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 11887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 11897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 11907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 11917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap(a.getInt( 11927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 11937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin(a.getInt( 11947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 11957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 11967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 11977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 11987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeOpacity = a.getFloat( 11997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 12007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 12017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 12027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 12037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 12047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 12057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 12067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 12079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 12089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 120963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui a.recycle(); 12109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 12119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 12129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private void updateColorAlphas() { 12139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mFillOpacity)) { 12142af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mFillColor = applyAlpha(mFillColor, mFillOpacity); 12159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 12169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 12179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mStrokeOpacity)) { 12182af745b56cf4bdfdd9c05d90a4ccc740bf77a4feztenghui mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity); 12199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 12209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 12219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1222abb7d134c02ac60091108c491dafb00877093170John Hoford private static int nextStart(String s, int end) { 1223abb7d134c02ac60091108c491dafb00877093170John Hoford char c; 1224abb7d134c02ac60091108c491dafb00877093170John Hoford 1225abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < s.length()) { 1226abb7d134c02ac60091108c491dafb00877093170John Hoford c = s.charAt(end); 1227abb7d134c02ac60091108c491dafb00877093170John Hoford if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { 1228abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 1229abb7d134c02ac60091108c491dafb00877093170John Hoford } 1230abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 1231abb7d134c02ac60091108c491dafb00877093170John Hoford } 1232abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 1233abb7d134c02ac60091108c491dafb00877093170John Hoford } 1234abb7d134c02ac60091108c491dafb00877093170John Hoford 1235abb7d134c02ac60091108c491dafb00877093170John Hoford private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) { 1236abb7d134c02ac60091108c491dafb00877093170John Hoford list.add(new VectorDrawable.VNode(cmd, val)); 1237abb7d134c02ac60091108c491dafb00877093170John Hoford } 1238abb7d134c02ac60091108c491dafb00877093170John Hoford 1239abb7d134c02ac60091108c491dafb00877093170John Hoford /** 1240abb7d134c02ac60091108c491dafb00877093170John Hoford * parse the floats in the string 1241abb7d134c02ac60091108c491dafb00877093170John Hoford * this is an optimized version of 1242abb7d134c02ac60091108c491dafb00877093170John Hoford * parseFloat(s.split(",|\\s")); 1243abb7d134c02ac60091108c491dafb00877093170John Hoford * 1244abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string containing a command and list of floats 1245abb7d134c02ac60091108c491dafb00877093170John Hoford * @return array of floats 1246abb7d134c02ac60091108c491dafb00877093170John Hoford */ 1247abb7d134c02ac60091108c491dafb00877093170John Hoford private static float[] getFloats(String s) { 1248abb7d134c02ac60091108c491dafb00877093170John Hoford if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { 1249abb7d134c02ac60091108c491dafb00877093170John Hoford return new float[0]; 1250abb7d134c02ac60091108c491dafb00877093170John Hoford } 1251abb7d134c02ac60091108c491dafb00877093170John Hoford try { 1252abb7d134c02ac60091108c491dafb00877093170John Hoford float[] tmp = new float[s.length()]; 1253abb7d134c02ac60091108c491dafb00877093170John Hoford int count = 0; 1254abb7d134c02ac60091108c491dafb00877093170John Hoford int pos = 1, end; 1255abb7d134c02ac60091108c491dafb00877093170John Hoford while ((end = extract(s, pos)) >= 0) { 1256abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < end) { 1257abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, end)); 1258abb7d134c02ac60091108c491dafb00877093170John Hoford } 1259abb7d134c02ac60091108c491dafb00877093170John Hoford pos = end + 1; 1260abb7d134c02ac60091108c491dafb00877093170John Hoford } 1261abb7d134c02ac60091108c491dafb00877093170John Hoford // handle the final float if there is one 1262abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < s.length()) { 1263abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, s.length())); 1264abb7d134c02ac60091108c491dafb00877093170John Hoford } 1265abb7d134c02ac60091108c491dafb00877093170John Hoford return Arrays.copyOf(tmp, count); 1266abb7d134c02ac60091108c491dafb00877093170John Hoford } catch (NumberFormatException e){ 1267abb7d134c02ac60091108c491dafb00877093170John Hoford Log.e(LOGTAG,"error in parsing \""+s+"\""); 1268abb7d134c02ac60091108c491dafb00877093170John Hoford throw e; 1269abb7d134c02ac60091108c491dafb00877093170John Hoford } 1270abb7d134c02ac60091108c491dafb00877093170John Hoford } 1271abb7d134c02ac60091108c491dafb00877093170John Hoford 1272abb7d134c02ac60091108c491dafb00877093170John Hoford /** 1273abb7d134c02ac60091108c491dafb00877093170John Hoford * calculate the position of the next comma or space 1274abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string to search 1275abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start the position to start searching 1276abb7d134c02ac60091108c491dafb00877093170John Hoford * @return the position of the next comma or space or -1 if none found 1277abb7d134c02ac60091108c491dafb00877093170John Hoford */ 1278abb7d134c02ac60091108c491dafb00877093170John Hoford private static int extract(String s, int start) { 1279abb7d134c02ac60091108c491dafb00877093170John Hoford int space = s.indexOf(' ', start); 1280abb7d134c02ac60091108c491dafb00877093170John Hoford int comma = s.indexOf(',', start); 1281abb7d134c02ac60091108c491dafb00877093170John Hoford if (space == -1) { 1282abb7d134c02ac60091108c491dafb00877093170John Hoford return comma; 1283abb7d134c02ac60091108c491dafb00877093170John Hoford } 1284abb7d134c02ac60091108c491dafb00877093170John Hoford if (comma == -1) { 1285abb7d134c02ac60091108c491dafb00877093170John Hoford return space; 1286abb7d134c02ac60091108c491dafb00877093170John Hoford } 1287abb7d134c02ac60091108c491dafb00877093170John Hoford return (comma > space) ? space : comma; 1288abb7d134c02ac60091108c491dafb00877093170John Hoford } 1289abb7d134c02ac60091108c491dafb00877093170John Hoford 1290abb7d134c02ac60091108c491dafb00877093170John Hoford private VectorDrawable.VNode[] parsePath(String value) { 1291abb7d134c02ac60091108c491dafb00877093170John Hoford int start = 0; 1292abb7d134c02ac60091108c491dafb00877093170John Hoford int end = 1; 1293abb7d134c02ac60091108c491dafb00877093170John Hoford 1294abb7d134c02ac60091108c491dafb00877093170John Hoford ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>(); 1295abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < value.length()) { 1296abb7d134c02ac60091108c491dafb00877093170John Hoford end = nextStart(value, end); 1297abb7d134c02ac60091108c491dafb00877093170John Hoford String s = value.substring(start, end); 1298abb7d134c02ac60091108c491dafb00877093170John Hoford float[] val = getFloats(s); 1299abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, s.charAt(0), val); 1300abb7d134c02ac60091108c491dafb00877093170John Hoford 1301abb7d134c02ac60091108c491dafb00877093170John Hoford start = end; 1302abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 1303abb7d134c02ac60091108c491dafb00877093170John Hoford } 1304abb7d134c02ac60091108c491dafb00877093170John Hoford if ((end - start) == 1 && start < value.length()) { 1305abb7d134c02ac60091108c491dafb00877093170John Hoford 1306abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, value.charAt(start), new float[0]); 1307abb7d134c02ac60091108c491dafb00877093170John Hoford } 1308abb7d134c02ac60091108c491dafb00877093170John Hoford return list.toArray(new VectorDrawable.VNode[list.size()]); 1309abb7d134c02ac60091108c491dafb00877093170John Hoford } 1310abb7d134c02ac60091108c491dafb00877093170John Hoford } 1311abb7d134c02ac60091108c491dafb00877093170John Hoford 1312abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VNode { 13135c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private char mType; 13145c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private float[] mParams; 13159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1316abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(char type, float[] params) { 13175c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = type; 13185c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = params; 1319abb7d134c02ac60091108c491dafb00877093170John Hoford } 1320abb7d134c02ac60091108c491dafb00877093170John Hoford 1321abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(VNode n) { 13225c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = n.mType; 13235c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = Arrays.copyOf(n.mParams, n.mParams.length); 1324abb7d134c02ac60091108c491dafb00877093170John Hoford } 1325abb7d134c02ac60091108c491dafb00877093170John Hoford 1326abb7d134c02ac60091108c491dafb00877093170John Hoford public static void createPath(VNode[] node, Path path) { 13275c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette float[] current = new float[4]; 132833ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCommand = 'm'; 1329abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < node.length; i++) { 133033ed52eff4b41f88858874e1af7723277a041b56ztenghui addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); 133133ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCommand = node[i].mType; 1332abb7d134c02ac60091108c491dafb00877093170John Hoford } 1333abb7d134c02ac60091108c491dafb00877093170John Hoford } 1334abb7d134c02ac60091108c491dafb00877093170John Hoford 133533ed52eff4b41f88858874e1af7723277a041b56ztenghui private static void addCommand(Path path, float[] current, 133633ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCmd, char cmd, float[] val) { 1337abb7d134c02ac60091108c491dafb00877093170John Hoford 1338abb7d134c02ac60091108c491dafb00877093170John Hoford int incr = 2; 1339abb7d134c02ac60091108c491dafb00877093170John Hoford float currentX = current[0]; 1340abb7d134c02ac60091108c491dafb00877093170John Hoford float currentY = current[1]; 1341abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointX = current[2]; 1342abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointY = current[3]; 134333ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointX; 134433ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointY; 1345abb7d134c02ac60091108c491dafb00877093170John Hoford 1346abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 1347abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': 1348abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': 1349abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 1350abb7d134c02ac60091108c491dafb00877093170John Hoford return; 1351abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': 1352abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': 1353abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': 1354abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': 1355abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': 1356abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': 1357abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 2; 1358abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1359abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': 1360abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': 1361abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': 1362abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': 1363abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 1; 1364abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1365abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': 1366abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': 1367abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 6; 1368abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1369abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': 1370abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': 1371abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': 1372abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': 1373abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 4; 1374abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1375abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': 1376abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': 1377abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 7; 1378abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1379abb7d134c02ac60091108c491dafb00877093170John Hoford } 1380abb7d134c02ac60091108c491dafb00877093170John Hoford for (int k = 0; k < val.length; k += incr) { 1381abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 1382abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': // moveto - Start a new sub-path (relative) 1383abb7d134c02ac60091108c491dafb00877093170John Hoford path.rMoveTo(val[k + 0], val[k + 1]); 1384abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1385abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1386abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1387abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': // moveto - Start a new sub-path 1388abb7d134c02ac60091108c491dafb00877093170John Hoford path.moveTo(val[k + 0], val[k + 1]); 1389abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1390abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1391abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1392abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': // lineto - Draw a line from the current point (relative) 1393abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], val[k + 1]); 1394abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1395abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1396abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1397abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': // lineto - Draw a line from the current point 1398abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], val[k + 1]); 1399abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1400abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1401abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1402abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': // closepath - Close the current subpath 1403abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': // closepath - Close the current subpath 1404abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 1405abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1406abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': // horizontal lineto - Draws a horizontal line (relative) 1407abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], 0); 1408abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1409abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1410abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': // horizontal lineto - Draws a horizontal line 1411abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], currentY); 1412abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1413abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1414abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': // vertical lineto - Draws a vertical line from the current point (r) 1415abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(0, val[k + 0]); 1416abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 0]; 1417abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1418abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': // vertical lineto - Draws a vertical line from the current point 1419abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(currentX, val[k + 0]); 1420abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 0]; 1421abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1422abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': // curveto - Draws a cubic Bézier curve (relative) 142333ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 142433ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1425abb7d134c02ac60091108c491dafb00877093170John Hoford 1426abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 2]; 1427abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 3]; 1428abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 4]; 1429abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 5]; 1430abb7d134c02ac60091108c491dafb00877093170John Hoford 1431abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1432abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': // curveto - Draws a cubic Bézier curve 143333ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 143433ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1435abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 4]; 1436abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 5]; 1437abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 2]; 1438abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 3]; 1439abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1440abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) 144133ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 144233ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 144333ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 144433ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 144533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 144633ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 144733ed52eff4b41f88858874e1af7723277a041b56ztenghui } 144833ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1449abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1], 1450abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], val[k + 3]); 1451abb7d134c02ac60091108c491dafb00877093170John Hoford 1452abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 0]; 1453abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 1]; 1454abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1455abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1456abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1457abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) 145833ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 145933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 146033ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 146133ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 146233ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 146333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 146433ed52eff4b41f88858874e1af7723277a041b56ztenghui } 146533ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 146633ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1467abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1468abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 146933ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 147033ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1471abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1472abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': // Draws a quadratic Bézier (relative) 1473abb7d134c02ac60091108c491dafb00877093170John Hoford path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 147433ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = currentX + val[k + 0]; 147533ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = currentY + val[k + 1]; 1476abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1477abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1478abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1479abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': // Draws a quadratic Bézier 1480abb7d134c02ac60091108c491dafb00877093170John Hoford path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1481abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1482abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 148333ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 148433ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1485abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1486abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) 148733ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 148833ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 148933ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 149033ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 149133ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 149233ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 149333ed52eff4b41f88858874e1af7723277a041b56ztenghui } 149433ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1495abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 1496175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointX = currentX + reflectiveCtrlPointX; 1497175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointY = currentY + reflectiveCtrlPointY; 1498abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1499abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1500abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1501abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': // Draws a quadratic Bézier curve (reflective control point) 150233ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 150333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 150433ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 150533ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 150633ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 150733ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 150833ed52eff4b41f88858874e1af7723277a041b56ztenghui } 150933ed52eff4b41f88858874e1af7723277a041b56ztenghui path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1510abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 151133ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = reflectiveCtrlPointX; 151233ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = reflectiveCtrlPointY; 1513abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 151433ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 1]; 1515abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1516abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': // Draws an elliptical arc 1517abb7d134c02ac60091108c491dafb00877093170John Hoford // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 1518abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1519abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1520abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1521abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5] + currentX, 1522abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6] + currentY, 1523abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1524abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1525abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1526abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1527abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1528abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 5]; 1529abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 6]; 1530abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1531abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1532abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1533abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': // Draws an elliptical arc 1534abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1535abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1536abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1537abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5], 1538abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6], 1539abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1540abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1541abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1542abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1543abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1544abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 5]; 1545abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 6]; 1546abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1547abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1548abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1549abb7d134c02ac60091108c491dafb00877093170John Hoford } 155033ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCmd = cmd; 1551abb7d134c02ac60091108c491dafb00877093170John Hoford } 1552abb7d134c02ac60091108c491dafb00877093170John Hoford current[0] = currentX; 1553abb7d134c02ac60091108c491dafb00877093170John Hoford current[1] = currentY; 1554abb7d134c02ac60091108c491dafb00877093170John Hoford current[2] = ctrlPointX; 1555abb7d134c02ac60091108c491dafb00877093170John Hoford current[3] = ctrlPointY; 1556abb7d134c02ac60091108c491dafb00877093170John Hoford } 1557abb7d134c02ac60091108c491dafb00877093170John Hoford 1558abb7d134c02ac60091108c491dafb00877093170John Hoford private static void drawArc(Path p, 1559abb7d134c02ac60091108c491dafb00877093170John Hoford float x0, 1560abb7d134c02ac60091108c491dafb00877093170John Hoford float y0, 1561abb7d134c02ac60091108c491dafb00877093170John Hoford float x1, 1562abb7d134c02ac60091108c491dafb00877093170John Hoford float y1, 1563abb7d134c02ac60091108c491dafb00877093170John Hoford float a, 1564abb7d134c02ac60091108c491dafb00877093170John Hoford float b, 1565abb7d134c02ac60091108c491dafb00877093170John Hoford float theta, 1566abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isMoreThanHalf, 1567abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isPositiveArc) { 1568abb7d134c02ac60091108c491dafb00877093170John Hoford 1569abb7d134c02ac60091108c491dafb00877093170John Hoford /* Convert rotation angle from degrees to radians */ 1570abb7d134c02ac60091108c491dafb00877093170John Hoford double thetaD = Math.toRadians(theta); 1571abb7d134c02ac60091108c491dafb00877093170John Hoford /* Pre-compute rotation matrix entries */ 1572abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(thetaD); 1573abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(thetaD); 1574abb7d134c02ac60091108c491dafb00877093170John Hoford /* Transform (x0, y0) and (x1, y1) into unit space */ 1575abb7d134c02ac60091108c491dafb00877093170John Hoford /* using (inverse) rotation, followed by (inverse) scale */ 1576abb7d134c02ac60091108c491dafb00877093170John Hoford double x0p = (x0 * cosTheta + y0 * sinTheta) / a; 1577abb7d134c02ac60091108c491dafb00877093170John Hoford double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; 1578abb7d134c02ac60091108c491dafb00877093170John Hoford double x1p = (x1 * cosTheta + y1 * sinTheta) / a; 1579abb7d134c02ac60091108c491dafb00877093170John Hoford double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; 1580abb7d134c02ac60091108c491dafb00877093170John Hoford 1581abb7d134c02ac60091108c491dafb00877093170John Hoford /* Compute differences and averages */ 1582abb7d134c02ac60091108c491dafb00877093170John Hoford double dx = x0p - x1p; 1583abb7d134c02ac60091108c491dafb00877093170John Hoford double dy = y0p - y1p; 1584abb7d134c02ac60091108c491dafb00877093170John Hoford double xm = (x0p + x1p) / 2; 1585abb7d134c02ac60091108c491dafb00877093170John Hoford double ym = (y0p + y1p) / 2; 1586abb7d134c02ac60091108c491dafb00877093170John Hoford /* Solve for intersecting unit circles */ 1587abb7d134c02ac60091108c491dafb00877093170John Hoford double dsq = dx * dx + dy * dy; 1588abb7d134c02ac60091108c491dafb00877093170John Hoford if (dsq == 0.0) { 1589abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, " Points are coincident"); 1590abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are coincident */ 1591abb7d134c02ac60091108c491dafb00877093170John Hoford } 1592abb7d134c02ac60091108c491dafb00877093170John Hoford double disc = 1.0 / dsq - 1.0 / 4.0; 1593abb7d134c02ac60091108c491dafb00877093170John Hoford if (disc < 0.0) { 1594abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, "Points are too far apart " + dsq); 1595abb7d134c02ac60091108c491dafb00877093170John Hoford float adjust = (float) (Math.sqrt(dsq) / 1.99999); 1596abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(p, x0, y0, x1, y1, a * adjust, 1597abb7d134c02ac60091108c491dafb00877093170John Hoford b * adjust, theta, isMoreThanHalf, isPositiveArc); 1598abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are too far apart */ 1599abb7d134c02ac60091108c491dafb00877093170John Hoford } 1600abb7d134c02ac60091108c491dafb00877093170John Hoford double s = Math.sqrt(disc); 1601abb7d134c02ac60091108c491dafb00877093170John Hoford double sdx = s * dx; 1602abb7d134c02ac60091108c491dafb00877093170John Hoford double sdy = s * dy; 1603abb7d134c02ac60091108c491dafb00877093170John Hoford double cx; 1604abb7d134c02ac60091108c491dafb00877093170John Hoford double cy; 1605abb7d134c02ac60091108c491dafb00877093170John Hoford if (isMoreThanHalf == isPositiveArc) { 1606abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm - sdy; 1607abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym + sdx; 1608abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1609abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm + sdy; 1610abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym - sdx; 1611abb7d134c02ac60091108c491dafb00877093170John Hoford } 1612abb7d134c02ac60091108c491dafb00877093170John Hoford 1613abb7d134c02ac60091108c491dafb00877093170John Hoford double eta0 = Math.atan2((y0p - cy), (x0p - cx)); 1614abb7d134c02ac60091108c491dafb00877093170John Hoford 1615abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = Math.atan2((y1p - cy), (x1p - cx)); 1616abb7d134c02ac60091108c491dafb00877093170John Hoford 1617abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep = (eta1 - eta0); 1618abb7d134c02ac60091108c491dafb00877093170John Hoford if (isPositiveArc != (sweep >= 0)) { 1619abb7d134c02ac60091108c491dafb00877093170John Hoford if (sweep > 0) { 1620abb7d134c02ac60091108c491dafb00877093170John Hoford sweep -= 2 * Math.PI; 1621abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1622abb7d134c02ac60091108c491dafb00877093170John Hoford sweep += 2 * Math.PI; 1623abb7d134c02ac60091108c491dafb00877093170John Hoford } 1624abb7d134c02ac60091108c491dafb00877093170John Hoford } 1625abb7d134c02ac60091108c491dafb00877093170John Hoford 1626abb7d134c02ac60091108c491dafb00877093170John Hoford cx *= a; 1627abb7d134c02ac60091108c491dafb00877093170John Hoford cy *= b; 1628abb7d134c02ac60091108c491dafb00877093170John Hoford double tcx = cx; 1629abb7d134c02ac60091108c491dafb00877093170John Hoford cx = cx * cosTheta - cy * sinTheta; 1630abb7d134c02ac60091108c491dafb00877093170John Hoford cy = tcx * sinTheta + cy * cosTheta; 1631abb7d134c02ac60091108c491dafb00877093170John Hoford 1632abb7d134c02ac60091108c491dafb00877093170John Hoford arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); 1633abb7d134c02ac60091108c491dafb00877093170John Hoford } 1634abb7d134c02ac60091108c491dafb00877093170John Hoford 1635abb7d134c02ac60091108c491dafb00877093170John Hoford /** 1636abb7d134c02ac60091108c491dafb00877093170John Hoford * Converts an arc to cubic Bezier segments and records them in p. 1637abb7d134c02ac60091108c491dafb00877093170John Hoford * 1638abb7d134c02ac60091108c491dafb00877093170John Hoford * @param p The target for the cubic Bezier segments 1639abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cx The x coordinate center of the ellipse 1640abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cy The y coordinate center of the ellipse 1641abb7d134c02ac60091108c491dafb00877093170John Hoford * @param a The radius of the ellipse in the horizontal direction 1642abb7d134c02ac60091108c491dafb00877093170John Hoford * @param b The radius of the ellipse in the vertical direction 1643abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1x E(eta1) x coordinate of the starting point of the arc 1644abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1y E(eta2) y coordinate of the starting point of the arc 1645abb7d134c02ac60091108c491dafb00877093170John Hoford * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane 1646abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start The start angle of the arc on the ellipse 1647abb7d134c02ac60091108c491dafb00877093170John Hoford * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse 1648abb7d134c02ac60091108c491dafb00877093170John Hoford */ 1649abb7d134c02ac60091108c491dafb00877093170John Hoford private static void arcToBezier(Path p, 1650abb7d134c02ac60091108c491dafb00877093170John Hoford double cx, 1651abb7d134c02ac60091108c491dafb00877093170John Hoford double cy, 1652abb7d134c02ac60091108c491dafb00877093170John Hoford double a, 1653abb7d134c02ac60091108c491dafb00877093170John Hoford double b, 1654abb7d134c02ac60091108c491dafb00877093170John Hoford double e1x, 1655abb7d134c02ac60091108c491dafb00877093170John Hoford double e1y, 1656abb7d134c02ac60091108c491dafb00877093170John Hoford double theta, 1657abb7d134c02ac60091108c491dafb00877093170John Hoford double start, 1658abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep) { 1659abb7d134c02ac60091108c491dafb00877093170John Hoford // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html 1660abb7d134c02ac60091108c491dafb00877093170John Hoford // and http://www.spaceroots.org/documents/ellipse/node22.html 1661abb7d134c02ac60091108c491dafb00877093170John Hoford 1662abb7d134c02ac60091108c491dafb00877093170John Hoford // Maximum of 45 degrees per cubic Bezier segment 1663abb7d134c02ac60091108c491dafb00877093170John Hoford int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); 1664abb7d134c02ac60091108c491dafb00877093170John Hoford 1665abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = start; 1666abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(theta); 1667abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(theta); 1668abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta1 = Math.cos(eta1); 1669abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta1 = Math.sin(eta1); 1670abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); 1671abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); 1672abb7d134c02ac60091108c491dafb00877093170John Hoford 1673abb7d134c02ac60091108c491dafb00877093170John Hoford double anglePerSegment = sweep / numSegments; 1674abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < numSegments; i++) { 1675abb7d134c02ac60091108c491dafb00877093170John Hoford double eta2 = eta1 + anglePerSegment; 1676abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta2 = Math.sin(eta2); 1677abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta2 = Math.cos(eta2); 1678abb7d134c02ac60091108c491dafb00877093170John Hoford double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); 1679abb7d134c02ac60091108c491dafb00877093170John Hoford double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); 1680abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; 1681abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; 1682abb7d134c02ac60091108c491dafb00877093170John Hoford double tanDiff2 = Math.tan((eta2 - eta1) / 2); 1683abb7d134c02ac60091108c491dafb00877093170John Hoford double alpha = 1684abb7d134c02ac60091108c491dafb00877093170John Hoford Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; 1685abb7d134c02ac60091108c491dafb00877093170John Hoford double q1x = e1x + alpha * ep1x; 1686abb7d134c02ac60091108c491dafb00877093170John Hoford double q1y = e1y + alpha * ep1y; 1687abb7d134c02ac60091108c491dafb00877093170John Hoford double q2x = e2x - alpha * ep2x; 1688abb7d134c02ac60091108c491dafb00877093170John Hoford double q2y = e2y - alpha * ep2y; 1689abb7d134c02ac60091108c491dafb00877093170John Hoford 1690abb7d134c02ac60091108c491dafb00877093170John Hoford p.cubicTo((float) q1x, 1691abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q1y, 1692abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2x, 1693abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2y, 1694abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2x, 1695abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2y); 1696abb7d134c02ac60091108c491dafb00877093170John Hoford eta1 = eta2; 1697abb7d134c02ac60091108c491dafb00877093170John Hoford e1x = e2x; 1698abb7d134c02ac60091108c491dafb00877093170John Hoford e1y = e2y; 1699abb7d134c02ac60091108c491dafb00877093170John Hoford ep1x = ep2x; 1700abb7d134c02ac60091108c491dafb00877093170John Hoford ep1y = ep2y; 1701abb7d134c02ac60091108c491dafb00877093170John Hoford } 1702abb7d134c02ac60091108c491dafb00877093170John Hoford } 1703abb7d134c02ac60091108c491dafb00877093170John Hoford 1704abb7d134c02ac60091108c491dafb00877093170John Hoford } 1705abb7d134c02ac60091108c491dafb00877093170John Hoford} 1706