VectorDrawable.java revision 63cfd85bcce488a3f3952bd1db523a727d30ca39
1abb7d134c02ac60091108c491dafb00877093170John Hoford/* 2abb7d134c02ac60091108c491dafb00877093170John Hoford * Copyright (C) 2014 The Android Open Source Project 3abb7d134c02ac60091108c491dafb00877093170John Hoford * 4abb7d134c02ac60091108c491dafb00877093170John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5abb7d134c02ac60091108c491dafb00877093170John Hoford * in compliance with the License. You may obtain a copy of the License at 6abb7d134c02ac60091108c491dafb00877093170John Hoford * 7abb7d134c02ac60091108c491dafb00877093170John Hoford * http://www.apache.org/licenses/LICENSE-2.0 8abb7d134c02ac60091108c491dafb00877093170John Hoford * 9abb7d134c02ac60091108c491dafb00877093170John Hoford * Unless required by applicable law or agreed to in writing, software distributed under the License 10abb7d134c02ac60091108c491dafb00877093170John Hoford * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11abb7d134c02ac60091108c491dafb00877093170John Hoford * or implied. See the License for the specific language governing permissions and limitations under 12abb7d134c02ac60091108c491dafb00877093170John Hoford * the License. 13abb7d134c02ac60091108c491dafb00877093170John Hoford */ 14abb7d134c02ac60091108c491dafb00877093170John Hoford 15abb7d134c02ac60091108c491dafb00877093170John Hofordpackage android.graphics.drawable; 16abb7d134c02ac60091108c491dafb00877093170John Hoford 17abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources; 18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme; 194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray; 20abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas; 21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter; 22abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix; 23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint; 24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path; 25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure; 26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat; 27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect; 28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region; 29abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet; 30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log; 314b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport android.util.Xml; 32abb7d134c02ac60091108c491dafb00877093170John Hoford 33abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R; 34abb7d134c02ac60091108c491dafb00877093170John Hoford 35abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser; 36abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException; 374b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport org.xmlpull.v1.XmlPullParserFactory; 38abb7d134c02ac60091108c491dafb00877093170John Hoford 39abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException; 40abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList; 41abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays; 42abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap; 434b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 44abb7d134c02ac60091108c491dafb00877093170John Hoford/** 45d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be 46d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code><vector></code> element. 47abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/> 4846e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The vector drawable has the following elements: 49abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/> 50abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl> 51177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code><vector></code></dt> 52e3c45e7a6b2a7d2176aa46ee482e299b54feeb9fztenghui * <dd>Used to defined a vector drawable</dd> 53abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><size></code></dt> 54abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using 55d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:width</code> and <code>android:height</code></dd> 56abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><viewport></code></dt> 57abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on. 58d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * The size is defined using the attributes <code>android:viewportHeight</code> 59d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:viewportWidth</code></dd> 606d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dt><code><group></code></dt> 616d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines a group of paths or subgroups, plus transformation information.</dd> 62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><path></code></dt> 636d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui * <dd>Defines paths to be drawn. 64abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl> 65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code> 66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt> 67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code> 6846e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines path string. This is using exactly same format as "d" attribute 6946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * in the SVG's path data</dd></dt> 70abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code> 71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt> 72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code> 73d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd> 74d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt> 75abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code> 76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt> 77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code> 78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt> 79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code> 80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt> 81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code> 82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt> 83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code> 84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt> 85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code> 86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt> 87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code> 88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt> 89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code> 90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt> 91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code> 92d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end) 93d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt> 94abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code> 95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt> 96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code> 97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt> 98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code> 99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt> 100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code> 101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt> 102abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl> 103abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd> 104abb7d134c02ac60091108c491dafb00877093170John Hoford */ 105abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable { 1069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private static final String LOGTAG = VectorDrawable.class.getSimpleName(); 1079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 108abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_SIZE = "size"; 109abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_VIEWPORT = "viewport"; 1106d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui private static final String SHAPE_GROUP = "group"; 111abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_PATH = "path"; 112abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_VECTOR = "vector"; 113abb7d134c02ac60091108c491dafb00877093170John Hoford 114abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_BUTT = 0; 115abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_ROUND = 1; 116abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_SQUARE = 2; 1179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 118abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_MITER = 0; 119abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_ROUND = 1; 120abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_BEVEL = 2; 1219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final VectorDrawableState mVectorState; 1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 124abb7d134c02ac60091108c491dafb00877093170John Hoford private int mAlpha = 0xFF; 125abb7d134c02ac60091108c491dafb00877093170John Hoford 126abb7d134c02ac60091108c491dafb00877093170John Hoford public VectorDrawable() { 1279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mVectorState = new VectorDrawableState(null); 128abb7d134c02ac60091108c491dafb00877093170John Hoford } 129abb7d134c02ac60091108c491dafb00877093170John Hoford 1309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) { 131abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState = new VectorDrawableState(state); 1329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (theme != null && canApplyTheme()) { 1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette applyTheme(theme); 1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 136abb7d134c02ac60091108c491dafb00877093170John Hoford } 137abb7d134c02ac60091108c491dafb00877093170John Hoford 138abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 139abb7d134c02ac60091108c491dafb00877093170John Hoford public ConstantState getConstantState() { 140abb7d134c02ac60091108c491dafb00877093170John Hoford return mVectorState; 141abb7d134c02ac60091108c491dafb00877093170John Hoford } 142abb7d134c02ac60091108c491dafb00877093170John Hoford 1434554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette @Override 144abb7d134c02ac60091108c491dafb00877093170John Hoford public void draw(Canvas canvas) { 1454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final int saveCount = canvas.save(); 1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Rect bounds = getBounds(); 1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.translate(bounds.left, bounds.top); 148ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); 1494b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.restoreToCount(saveCount); 150abb7d134c02ac60091108c491dafb00877093170John Hoford } 151abb7d134c02ac60091108c491dafb00877093170John Hoford 152abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 153abb7d134c02ac60091108c491dafb00877093170John Hoford public void setAlpha(int alpha) { 154abb7d134c02ac60091108c491dafb00877093170John Hoford // TODO correct handling of transparent 155abb7d134c02ac60091108c491dafb00877093170John Hoford if (mAlpha != alpha) { 156abb7d134c02ac60091108c491dafb00877093170John Hoford mAlpha = alpha; 157abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 158abb7d134c02ac60091108c491dafb00877093170John Hoford } 159abb7d134c02ac60091108c491dafb00877093170John Hoford } 160abb7d134c02ac60091108c491dafb00877093170John Hoford 161abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 162abb7d134c02ac60091108c491dafb00877093170John Hoford public void setColorFilter(ColorFilter colorFilter) { 163fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mVectorState.mVPathRenderer.setColorFilter(colorFilter); 164fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette invalidateSelf(); 165abb7d134c02ac60091108c491dafb00877093170John Hoford } 166abb7d134c02ac60091108c491dafb00877093170John Hoford 167abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 168abb7d134c02ac60091108c491dafb00877093170John Hoford public int getOpacity() { 169abb7d134c02ac60091108c491dafb00877093170John Hoford return PixelFormat.TRANSLUCENT; 170abb7d134c02ac60091108c491dafb00877093170John Hoford } 171abb7d134c02ac60091108c491dafb00877093170John Hoford 172abb7d134c02ac60091108c491dafb00877093170John Hoford /** 173d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * Sets padding for this shape, defined by a Rect object. Define the padding 174d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * in the Rect object as: left, top, right, bottom. 175abb7d134c02ac60091108c491dafb00877093170John Hoford */ 176abb7d134c02ac60091108c491dafb00877093170John Hoford public void setPadding(Rect padding) { 177abb7d134c02ac60091108c491dafb00877093170John Hoford setPadding(padding.left, padding.top, padding.right, padding.bottom); 178abb7d134c02ac60091108c491dafb00877093170John Hoford } 179abb7d134c02ac60091108c491dafb00877093170John Hoford 180abb7d134c02ac60091108c491dafb00877093170John Hoford /** 181abb7d134c02ac60091108c491dafb00877093170John Hoford * Sets padding for the shape. 182abb7d134c02ac60091108c491dafb00877093170John Hoford * 183abb7d134c02ac60091108c491dafb00877093170John Hoford * @param left padding for the left side (in pixels) 184abb7d134c02ac60091108c491dafb00877093170John Hoford * @param top padding for the top (in pixels) 185abb7d134c02ac60091108c491dafb00877093170John Hoford * @param right padding for the right side (in pixels) 186abb7d134c02ac60091108c491dafb00877093170John Hoford * @param bottom padding for the bottom (in pixels) 187abb7d134c02ac60091108c491dafb00877093170John Hoford */ 188abb7d134c02ac60091108c491dafb00877093170John Hoford public void setPadding(int left, int top, int right, int bottom) { 189abb7d134c02ac60091108c491dafb00877093170John Hoford if ((left | top | right | bottom) == 0) { 190abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding = null; 191abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 192abb7d134c02ac60091108c491dafb00877093170John Hoford if (mVectorState.mPadding == null) { 193abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding = new Rect(); 194abb7d134c02ac60091108c491dafb00877093170John Hoford } 195abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding.set(left, top, right, bottom); 196abb7d134c02ac60091108c491dafb00877093170John Hoford } 197abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 198abb7d134c02ac60091108c491dafb00877093170John Hoford } 199abb7d134c02ac60091108c491dafb00877093170John Hoford 200abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 201abb7d134c02ac60091108c491dafb00877093170John Hoford public int getIntrinsicWidth() { 202ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return (int) mVectorState.mVPathRenderer.mBaseWidth; 203abb7d134c02ac60091108c491dafb00877093170John Hoford } 204abb7d134c02ac60091108c491dafb00877093170John Hoford 205abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 206abb7d134c02ac60091108c491dafb00877093170John Hoford public int getIntrinsicHeight() { 207ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return (int) mVectorState.mVPathRenderer.mBaseHeight; 208abb7d134c02ac60091108c491dafb00877093170John Hoford } 209abb7d134c02ac60091108c491dafb00877093170John Hoford 210abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 211abb7d134c02ac60091108c491dafb00877093170John Hoford public boolean getPadding(Rect padding) { 212abb7d134c02ac60091108c491dafb00877093170John Hoford if (mVectorState.mPadding != null) { 213abb7d134c02ac60091108c491dafb00877093170John Hoford padding.set(mVectorState.mPadding); 214abb7d134c02ac60091108c491dafb00877093170John Hoford return true; 215abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 216abb7d134c02ac60091108c491dafb00877093170John Hoford return super.getPadding(padding); 217abb7d134c02ac60091108c491dafb00877093170John Hoford } 218abb7d134c02ac60091108c491dafb00877093170John Hoford } 219abb7d134c02ac60091108c491dafb00877093170John Hoford 220abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 221abb7d134c02ac60091108c491dafb00877093170John Hoford public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) 222abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException, IOException { 223ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer p = inflateInternal(res, parser, attrs, theme); 224ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui setPathRenderer(p); 225abb7d134c02ac60091108c491dafb00877093170John Hoford } 226abb7d134c02ac60091108c491dafb00877093170John Hoford 2279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette @Override 2289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 2299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme(); 2309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette @Override 2339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 2349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette super.applyTheme(t); 2359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VectorDrawableState state = mVectorState; 237ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer path = state.mVPathRenderer; 2389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (path != null && path.canApplyTheme()) { 2399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.applyTheme(t); 2409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2434b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette /** @hide */ 2444b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette public static VectorDrawable create(Resources resources, int rid) { 2454b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette try { 2464b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final XmlPullParser xpp = resources.getXml(rid); 2474b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final AttributeSet attrs = Xml.asAttributeSet(xpp); 2484b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 2494b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette factory.setNamespaceAware(true); 2504b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 2514b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final VectorDrawable drawable = new VectorDrawable(); 2524b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette drawable.inflate(resources, xpp, attrs); 2534b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 2544b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette return drawable; 2554b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } catch (XmlPullParserException e) { 2564b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette Log.e(LOGTAG, "parser error", e); 2574b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } catch (IOException e) { 2584b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette Log.e(LOGTAG, "parser error", e); 2594b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } 2604b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette return null; 2614b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } 2624b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 263ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, 2649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette Theme theme) throws XmlPullParserException, IOException { 265ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer pathRenderer = new VPathRenderer(); 2669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 267abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noSizeTag = true; 268abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noViewportTag = true; 2696d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui boolean noGroupTag = true; 270abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noPathTag = true; 2719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 27246e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui VGroup currentGroup = new VGroup(); 273abb7d134c02ac60091108c491dafb00877093170John Hoford 274abb7d134c02ac60091108c491dafb00877093170John Hoford int eventType = parser.getEventType(); 275abb7d134c02ac60091108c491dafb00877093170John Hoford while (eventType != XmlPullParser.END_DOCUMENT) { 276abb7d134c02ac60091108c491dafb00877093170John Hoford if (eventType == XmlPullParser.START_TAG) { 2779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final String tagName = parser.getName(); 278abb7d134c02ac60091108c491dafb00877093170John Hoford if (SHAPE_PATH.equals(tagName)) { 2799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VPath path = new VPath(); 2809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.inflate(res, attrs, theme); 2819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette currentGroup.add(path); 282abb7d134c02ac60091108c491dafb00877093170John Hoford noPathTag = false; 283abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_SIZE.equals(tagName)) { 284ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseSize(res, attrs); 285abb7d134c02ac60091108c491dafb00877093170John Hoford noSizeTag = false; 286abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_VIEWPORT.equals(tagName)) { 287ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseViewport(res, attrs); 288abb7d134c02ac60091108c491dafb00877093170John Hoford noViewportTag = false; 2896d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui } else if (SHAPE_GROUP.equals(tagName)) { 2906d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui currentGroup = new VGroup(); 29163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui currentGroup.inflate(res, attrs, theme); 2926d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui pathRenderer.mGroupList.add(currentGroup); 2936d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui noGroupTag = false; 294abb7d134c02ac60091108c491dafb00877093170John Hoford } 295abb7d134c02ac60091108c491dafb00877093170John Hoford } 2969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 297abb7d134c02ac60091108c491dafb00877093170John Hoford eventType = parser.next(); 298abb7d134c02ac60091108c491dafb00877093170John Hoford } 2999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3006d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui if (noGroupTag && !noPathTag) { 3016d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui pathRenderer.mGroupList.add(currentGroup); 3026d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui } 3036d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui 30446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui if (noSizeTag || noViewportTag || noPathTag) { 3059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final StringBuffer tag = new StringBuffer(); 3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 307abb7d134c02ac60091108c491dafb00877093170John Hoford if (noSizeTag) { 3089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 309abb7d134c02ac60091108c491dafb00877093170John Hoford } 3109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 311d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noViewportTag) { 312d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 313abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" & "); 314abb7d134c02ac60091108c491dafb00877093170John Hoford } 3159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 316abb7d134c02ac60091108c491dafb00877093170John Hoford } 3179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 318d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noPathTag) { 319d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 320abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" or "); 321abb7d134c02ac60091108c491dafb00877093170John Hoford } 3229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_PATH); 323abb7d134c02ac60091108c491dafb00877093170John Hoford } 3249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette throw new XmlPullParserException("no " + tag + " defined"); 326abb7d134c02ac60091108c491dafb00877093170John Hoford } 3279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 328ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return pathRenderer; 329abb7d134c02ac60091108c491dafb00877093170John Hoford } 330abb7d134c02ac60091108c491dafb00877093170John Hoford 331ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private void setPathRenderer(VPathRenderer pathRenderer) { 332ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer = pathRenderer; 333abb7d134c02ac60091108c491dafb00877093170John Hoford } 334abb7d134c02ac60091108c491dafb00877093170John Hoford 3355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private static class VectorDrawableState extends ConstantState { 3365c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette int mChangingConfigurations; 337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui VPathRenderer mVPathRenderer; 3385c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette Rect mPadding; 3395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public VectorDrawableState(VectorDrawableState copy) { 3415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette if (copy != null) { 3425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mChangingConfigurations = copy.mChangingConfigurations; 343ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); 3445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mPadding = new Rect(copy.mPadding); 3455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable() { 3505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, null, null); 3515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res) { 3555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, null); 3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res, Theme theme) { 3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, theme); 3615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public int getChangingConfigurations() { 3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return mChangingConfigurations; 3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 369ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private static class VPathRenderer { 3704b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mPath = new Path(); 3714b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mRenderPath = new Path(); 3724b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Matrix mMatrix = new Matrix(); 3734b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 3744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mStrokePaint; 3754b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mFillPaint; 376fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette private ColorFilter mColorFilter; 377abb7d134c02ac60091108c491dafb00877093170John Hoford private PathMeasure mPathMeasure; 3784b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 3796d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>(); 3809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 381fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette float mBaseWidth = 0; 382fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette float mBaseHeight = 0; 383fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette float mViewportWidth = 0; 384fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette float mViewportHeight = 0; 385abb7d134c02ac60091108c491dafb00877093170John Hoford 386ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer() { 387abb7d134c02ac60091108c491dafb00877093170John Hoford } 3889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 389ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer(VPathRenderer copy) { 3906d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui mGroupList.addAll(copy.mGroupList); 391abb7d134c02ac60091108c491dafb00877093170John Hoford 392abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseWidth = copy.mBaseWidth; 393abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseHeight = copy.mBaseHeight; 394abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportWidth = copy.mViewportHeight; 395abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportHeight = copy.mViewportHeight; 396abb7d134c02ac60091108c491dafb00877093170John Hoford } 397abb7d134c02ac60091108c491dafb00877093170John Hoford 3989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 3996d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui final ArrayList<VGroup> groups = mGroupList; 4006d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui for (int i = groups.size() - 1; i >= 0; i--) { 4016d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui final ArrayList<VPath> paths = groups.get(i).mVGList; 4026d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui for (int j = paths.size() - 1; j >= 0; j--) { 4036d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui final VPath path = paths.get(j); 4046d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui if (path.canApplyTheme()) { 4056d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui return true; 4066d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui } 4079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4096d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui 4109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return false; 4119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 4139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 4146d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui final ArrayList<VGroup> groups = mGroupList; 4156d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui for (int i = groups.size() - 1; i >= 0; i--) { 41663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui VGroup currentGroup = groups.get(i); 41763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui currentGroup.applyTheme(t); 41863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final ArrayList<VPath> paths = currentGroup.mVGList; 4196d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui for (int j = paths.size() - 1; j >= 0; j--) { 4206d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui final VPath path = paths.get(j); 4216d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui if (path.canApplyTheme()) { 4226d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui path.applyTheme(t); 4236d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui } 4249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 426abb7d134c02ac60091108c491dafb00877093170John Hoford } 427abb7d134c02ac60091108c491dafb00877093170John Hoford 428fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette public void setColorFilter(ColorFilter colorFilter) { 429fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mColorFilter = colorFilter; 430fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 431fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mFillPaint != null) { 432fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mFillPaint.setColorFilter(colorFilter); 433fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } 434fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 435fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mStrokePaint != null) { 436fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mStrokePaint.setColorFilter(colorFilter); 437fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } 4386d9c422de5e0a3890dd723cb1b9264d4507053e9ztenghui 439fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } 440fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 4414b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette public void draw(Canvas canvas, int w, int h) { 44263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mGroupList == null || mGroupList.size() == 0) { 44363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui Log.e(LOGTAG,"There is no group to draw"); 444abb7d134c02ac60091108c491dafb00877093170John Hoford return; 445abb7d134c02ac60091108c491dafb00877093170John Hoford } 446abb7d134c02ac60091108c491dafb00877093170John Hoford 44763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui for (int i = 0; i < mGroupList.size(); i++) { 44863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui VGroup currentGroup = mGroupList.get(i); 44963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (currentGroup != null) { 45063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui drawPath(currentGroup, canvas, w, h); 451abb7d134c02ac60091108c491dafb00877093170John Hoford } 452abb7d134c02ac60091108c491dafb00877093170John Hoford } 453abb7d134c02ac60091108c491dafb00877093170John Hoford } 454abb7d134c02ac60091108c491dafb00877093170John Hoford 45563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private void drawPath(VGroup vGroup, Canvas canvas, int w, int h) { 4569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final float scale = Math.min(h / mViewportHeight, w / mViewportWidth); 457abb7d134c02ac60091108c491dafb00877093170John Hoford 458abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.reset(); 459abb7d134c02ac60091108c491dafb00877093170John Hoford 46063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mMatrix.postRotate(vGroup.mRotate, vGroup.mPivotX, vGroup.mPivotY); 461abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f); 462abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f); 463abb7d134c02ac60091108c491dafb00877093170John Hoford 46463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui ArrayList<VPath> paths = vGroup.getPaths(); 46563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui for (int i = 0; i < paths.size(); i++) { 46663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui VPath vPath = paths.get(i); 46763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui vPath.toPath(mPath); 46863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final Path path = mPath; 469abb7d134c02ac60091108c491dafb00877093170John Hoford 47063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { 47163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; 47263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f; 4739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 47463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mPathMeasure == null) { 47563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure = new PathMeasure(); 47663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 47763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.setPath(mPath, false); 47863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 47963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui float len = mPathMeasure.getLength(); 48063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui start = start * len; 48163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui end = end * len; 48263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui path.reset(); 48363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (start > end) { 48463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.getSegment(start, len, path, true); 48563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.getSegment(0f, end, path, true); 48663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } else { 48763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPathMeasure.getSegment(start, end, path, true); 48863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 48963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui path.rLineTo(0, 0); // fix bug in measure 4904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette } 4914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 49263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRenderPath.reset(); 4939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 49463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRenderPath.addPath(path, mMatrix); 4954b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 49663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mClip) { 49763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui canvas.clipPath(mRenderPath, Region.Op.REPLACE); 498abb7d134c02ac60091108c491dafb00877093170John Hoford } 4994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 50063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mFillColor != 0) { 50163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mFillPaint == null) { 50263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mFillPaint = new Paint(); 50363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mFillPaint.setColorFilter(mColorFilter); 50463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mFillPaint.setStyle(Paint.Style.FILL); 50563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mFillPaint.setAntiAlias(true); 50663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 50763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 50863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mFillPaint.setColor(vPath.mFillColor); 50963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui canvas.drawPath(mRenderPath, mFillPaint); 510abb7d134c02ac60091108c491dafb00877093170John Hoford } 5114b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 51263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mStrokeColor != 0) { 51363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mStrokePaint == null) { 51463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mStrokePaint = new Paint(); 51563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mStrokePaint.setColorFilter(mColorFilter); 51663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mStrokePaint.setStyle(Paint.Style.STROKE); 51763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mStrokePaint.setAntiAlias(true); 51863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 519abb7d134c02ac60091108c491dafb00877093170John Hoford 52063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final Paint strokePaint = mStrokePaint; 52163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mStrokeLineJoin != null) { 52263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); 52363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 52463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 52563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (vPath.mStrokeLineCap != null) { 52663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui strokePaint.setStrokeCap(vPath.mStrokeLineCap); 52763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 52863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 52963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); 53063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui strokePaint.setColor(vPath.mStrokeColor); 53163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); 53263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui canvas.drawPath(mRenderPath, strokePaint); 53363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 534abb7d134c02ac60091108c491dafb00877093170John Hoford } 535abb7d134c02ac60091108c491dafb00877093170John Hoford } 536abb7d134c02ac60091108c491dafb00877093170John Hoford 537abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseViewport(Resources r, AttributeSet attrs) 538abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 5394b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); 540fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, mViewportWidth); 541fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, mViewportHeight); 542fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 543fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mViewportWidth <= 0) { 544fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 545fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<viewport> tag requires viewportWidth > 0"); 546fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } else if (mViewportHeight <= 0) { 547fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 548fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<viewport> tag requires viewportHeight > 0"); 549abb7d134c02ac60091108c491dafb00877093170John Hoford } 550fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 551abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 552abb7d134c02ac60091108c491dafb00877093170John Hoford } 553abb7d134c02ac60091108c491dafb00877093170John Hoford 554abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseSize(Resources r, AttributeSet attrs) 555abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 5564b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); 557fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, mBaseWidth); 558fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, mBaseHeight); 559fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 560fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette if (mBaseWidth <= 0) { 561fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 562fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<size> tag requires width > 0"); 563fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette } else if (mBaseHeight <= 0) { 564fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette throw new XmlPullParserException(a.getPositionDescription() + 565fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette "<size> tag requires height > 0"); 566abb7d134c02ac60091108c491dafb00877093170John Hoford } 567fd6e411767735478ee0f69ba01d77def4c6b2627Alan Viverette 568abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 569abb7d134c02ac60091108c491dafb00877093170John Hoford } 5704b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 571abb7d134c02ac60091108c491dafb00877093170John Hoford } 572abb7d134c02ac60091108c491dafb00877093170John Hoford 573abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VGroup { 5749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>(); 5759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private final ArrayList<VPath> mVGList = new ArrayList<VPath>(); 576abb7d134c02ac60091108c491dafb00877093170John Hoford 57763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private float mRotate = 0; 57863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private float mPivotX = 0; 57963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private float mPivotY = 0; 58063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 58163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui private int[] mThemeAttrs; 58263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 583abb7d134c02ac60091108c491dafb00877093170John Hoford public void add(VPath path) { 584abb7d134c02ac60091108c491dafb00877093170John Hoford String id = path.getID(); 585abb7d134c02ac60091108c491dafb00877093170John Hoford mVGPathMap.put(id, path); 586abb7d134c02ac60091108c491dafb00877093170John Hoford mVGList.add(path); 587abb7d134c02ac60091108c491dafb00877093170John Hoford } 588abb7d134c02ac60091108c491dafb00877093170John Hoford 58963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui public void applyTheme(Theme t) { 59063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (mThemeAttrs == null) { 59163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui return; 59263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 59363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 59463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final TypedArray a = t.resolveAttributes( 59563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mThemeAttrs, R.styleable.VectorDrawablePath); 59663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 59763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); 59863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); 59963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); 60063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui a.recycle(); 60163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 60263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 60363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui public void inflate(Resources res, AttributeSet attrs, Theme theme) { 60463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup); 60563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui final int[] themeAttrs = a.extractThemeAttrs(); 60663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 60763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mThemeAttrs = themeAttrs; 60863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui // NOTE: The set of attributes loaded here MUST match the 60963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui // set of attributes loaded in applyTheme. 61063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 61163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) { 61263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); 61363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 61463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 61563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) { 61663cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); 61763cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 61863cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 61963cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) { 62063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); 62163cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 62263cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 62363cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui a.recycle(); 62463cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui } 62563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui 626abb7d134c02ac60091108c491dafb00877093170John Hoford /** 627abb7d134c02ac60091108c491dafb00877093170John Hoford * Must return in order of adding 628abb7d134c02ac60091108c491dafb00877093170John Hoford * @return ordered list of paths 629abb7d134c02ac60091108c491dafb00877093170John Hoford */ 63063cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui public ArrayList<VPath> getPaths() { 631abb7d134c02ac60091108c491dafb00877093170John Hoford return mVGList; 632abb7d134c02ac60091108c491dafb00877093170John Hoford } 633abb7d134c02ac60091108c491dafb00877093170John Hoford 634abb7d134c02ac60091108c491dafb00877093170John Hoford } 635abb7d134c02ac60091108c491dafb00877093170John Hoford 636abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VPath { 637abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int MAX_STATES = 10; 6389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private int[] mThemeAttrs; 6409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 641abb7d134c02ac60091108c491dafb00877093170John Hoford int mStrokeColor = 0; 642abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeWidth = 0; 643abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeOpacity = Float.NaN; 6449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 645abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillColor = 0; 646abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillRule; 647abb7d134c02ac60091108c491dafb00877093170John Hoford float mFillOpacity = Float.NaN; 6489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 649abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathStart = 0; 650abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathEnd = 1; 651abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathOffset = 0; 6529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 653abb7d134c02ac60091108c491dafb00877093170John Hoford boolean mClip = false; 6544b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; 6554b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Join mStrokeLineJoin = Paint.Join.MITER; 656abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeMiterlimit = 4; 6579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VNode[] mNode = null; 6599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private String mId; 660abb7d134c02ac60091108c491dafb00877093170John Hoford 6619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public VPath() { 6629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette // Empty constructor. 6639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 665abb7d134c02ac60091108c491dafb00877093170John Hoford public void toPath(Path path) { 666abb7d134c02ac60091108c491dafb00877093170John Hoford path.reset(); 667abb7d134c02ac60091108c491dafb00877093170John Hoford if (mNode != null) { 668abb7d134c02ac60091108c491dafb00877093170John Hoford VNode.createPath(mNode, path); 669abb7d134c02ac60091108c491dafb00877093170John Hoford } 670abb7d134c02ac60091108c491dafb00877093170John Hoford } 671abb7d134c02ac60091108c491dafb00877093170John Hoford 6727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette public String getID() { 673abb7d134c02ac60091108c491dafb00877093170John Hoford return mId; 674abb7d134c02ac60091108c491dafb00877093170John Hoford } 675abb7d134c02ac60091108c491dafb00877093170John Hoford 6767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { 6777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 6787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_BUTT: 6797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.BUTT; 6807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_ROUND: 6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.ROUND; 6827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_SQUARE: 6837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.SQUARE; 6847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) { 6907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 6917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_MITER: 6927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.MITER; 6937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_ROUND: 6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.ROUND; 6957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_BEVEL: 6967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.BEVEL; 6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 6997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void inflate(Resources r, AttributeSet attrs, Theme theme) { 7039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath); 7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final int[] themeAttrs = a.extractThemeAttrs(); 7059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mThemeAttrs = themeAttrs; 7069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // NOTE: The set of attributes loaded here MUST match the 7087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // set of attributes loaded in applyTheme. 7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) { 7107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 7117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) { 7147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mId = a.getString(R.styleable.VectorDrawablePath_name); 7157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) { 7187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 7197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 720abb7d134c02ac60091108c491dafb00877093170John Hoford 7219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) { 7227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 7239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) { 7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 727abb7d134c02ac60091108c491dafb00877093170John Hoford } 7289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) { 7317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap( 7327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 7337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) { 7377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin( 7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 739abb7d134c02ac60091108c491dafb00877093170John Hoford } 7409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) { 7437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 7447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 7457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) { 7489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 749abb7d134c02ac60091108c491dafb00877093170John Hoford } 7509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null 7529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) { 7539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeOpacity = a.getFloat( 7547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 7559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) { 7587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 7597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) { 7627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 7637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7649453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) { 7677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 7687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 7697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) { 7737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 7747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 7757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 7789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 779abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 780abb7d134c02ac60091108c491dafb00877093170John Hoford } 781abb7d134c02ac60091108c491dafb00877093170John Hoford 7829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 7839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return mThemeAttrs != null; 7849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 7879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (mThemeAttrs == null) { 7889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return; 7899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = t.resolveAttributes( 7920cfb877f5a0a1bff82d9c3ee969195bf7812c0b5Alan Viverette mThemeAttrs, R.styleable.VectorDrawablePath); 7939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 7959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_name)) { 7977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mId = a.getString(R.styleable.VectorDrawablePath_name); 7989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) { 8017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 8029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 8057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 8067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 8077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap(a.getInt( 8087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 8097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin(a.getInt( 8107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 8117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 8127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 8137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 8147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeOpacity = a.getFloat( 8157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 8167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 8177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 8187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 8197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 8207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 8217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 8227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 8239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 82563cfd85bcce488a3f3952bd1db523a727d30ca39ztenghui a.recycle(); 8269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private void updateColorAlphas() { 8299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mFillOpacity)) { 8309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mFillColor &= 0x00FFFFFF; 8319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mFillColor |= ((int) (0xFF * mFillOpacity)) << 24; 8329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mStrokeOpacity)) { 8359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor &= 0x00FFFFFF; 8369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24; 8379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 840abb7d134c02ac60091108c491dafb00877093170John Hoford private static int nextStart(String s, int end) { 841abb7d134c02ac60091108c491dafb00877093170John Hoford char c; 842abb7d134c02ac60091108c491dafb00877093170John Hoford 843abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < s.length()) { 844abb7d134c02ac60091108c491dafb00877093170John Hoford c = s.charAt(end); 845abb7d134c02ac60091108c491dafb00877093170John Hoford if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { 846abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 847abb7d134c02ac60091108c491dafb00877093170John Hoford } 848abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 849abb7d134c02ac60091108c491dafb00877093170John Hoford } 850abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 851abb7d134c02ac60091108c491dafb00877093170John Hoford } 852abb7d134c02ac60091108c491dafb00877093170John Hoford 853abb7d134c02ac60091108c491dafb00877093170John Hoford private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) { 854abb7d134c02ac60091108c491dafb00877093170John Hoford list.add(new VectorDrawable.VNode(cmd, val)); 855abb7d134c02ac60091108c491dafb00877093170John Hoford } 856abb7d134c02ac60091108c491dafb00877093170John Hoford 857abb7d134c02ac60091108c491dafb00877093170John Hoford /** 858abb7d134c02ac60091108c491dafb00877093170John Hoford * parse the floats in the string 859abb7d134c02ac60091108c491dafb00877093170John Hoford * this is an optimized version of 860abb7d134c02ac60091108c491dafb00877093170John Hoford * parseFloat(s.split(",|\\s")); 861abb7d134c02ac60091108c491dafb00877093170John Hoford * 862abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string containing a command and list of floats 863abb7d134c02ac60091108c491dafb00877093170John Hoford * @return array of floats 864abb7d134c02ac60091108c491dafb00877093170John Hoford */ 865abb7d134c02ac60091108c491dafb00877093170John Hoford private static float[] getFloats(String s) { 866abb7d134c02ac60091108c491dafb00877093170John Hoford if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { 867abb7d134c02ac60091108c491dafb00877093170John Hoford return new float[0]; 868abb7d134c02ac60091108c491dafb00877093170John Hoford } 869abb7d134c02ac60091108c491dafb00877093170John Hoford try { 870abb7d134c02ac60091108c491dafb00877093170John Hoford float[] tmp = new float[s.length()]; 871abb7d134c02ac60091108c491dafb00877093170John Hoford int count = 0; 872abb7d134c02ac60091108c491dafb00877093170John Hoford int pos = 1, end; 873abb7d134c02ac60091108c491dafb00877093170John Hoford while ((end = extract(s, pos)) >= 0) { 874abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < end) { 875abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, end)); 876abb7d134c02ac60091108c491dafb00877093170John Hoford } 877abb7d134c02ac60091108c491dafb00877093170John Hoford pos = end + 1; 878abb7d134c02ac60091108c491dafb00877093170John Hoford } 879abb7d134c02ac60091108c491dafb00877093170John Hoford // handle the final float if there is one 880abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < s.length()) { 881abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, s.length())); 882abb7d134c02ac60091108c491dafb00877093170John Hoford } 883abb7d134c02ac60091108c491dafb00877093170John Hoford return Arrays.copyOf(tmp, count); 884abb7d134c02ac60091108c491dafb00877093170John Hoford } catch (NumberFormatException e){ 885abb7d134c02ac60091108c491dafb00877093170John Hoford Log.e(LOGTAG,"error in parsing \""+s+"\""); 886abb7d134c02ac60091108c491dafb00877093170John Hoford throw e; 887abb7d134c02ac60091108c491dafb00877093170John Hoford } 888abb7d134c02ac60091108c491dafb00877093170John Hoford } 889abb7d134c02ac60091108c491dafb00877093170John Hoford 890abb7d134c02ac60091108c491dafb00877093170John Hoford /** 891abb7d134c02ac60091108c491dafb00877093170John Hoford * calculate the position of the next comma or space 892abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string to search 893abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start the position to start searching 894abb7d134c02ac60091108c491dafb00877093170John Hoford * @return the position of the next comma or space or -1 if none found 895abb7d134c02ac60091108c491dafb00877093170John Hoford */ 896abb7d134c02ac60091108c491dafb00877093170John Hoford private static int extract(String s, int start) { 897abb7d134c02ac60091108c491dafb00877093170John Hoford int space = s.indexOf(' ', start); 898abb7d134c02ac60091108c491dafb00877093170John Hoford int comma = s.indexOf(',', start); 899abb7d134c02ac60091108c491dafb00877093170John Hoford if (space == -1) { 900abb7d134c02ac60091108c491dafb00877093170John Hoford return comma; 901abb7d134c02ac60091108c491dafb00877093170John Hoford } 902abb7d134c02ac60091108c491dafb00877093170John Hoford if (comma == -1) { 903abb7d134c02ac60091108c491dafb00877093170John Hoford return space; 904abb7d134c02ac60091108c491dafb00877093170John Hoford } 905abb7d134c02ac60091108c491dafb00877093170John Hoford return (comma > space) ? space : comma; 906abb7d134c02ac60091108c491dafb00877093170John Hoford } 907abb7d134c02ac60091108c491dafb00877093170John Hoford 908abb7d134c02ac60091108c491dafb00877093170John Hoford private VectorDrawable.VNode[] parsePath(String value) { 909abb7d134c02ac60091108c491dafb00877093170John Hoford int start = 0; 910abb7d134c02ac60091108c491dafb00877093170John Hoford int end = 1; 911abb7d134c02ac60091108c491dafb00877093170John Hoford 912abb7d134c02ac60091108c491dafb00877093170John Hoford ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>(); 913abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < value.length()) { 914abb7d134c02ac60091108c491dafb00877093170John Hoford end = nextStart(value, end); 915abb7d134c02ac60091108c491dafb00877093170John Hoford String s = value.substring(start, end); 916abb7d134c02ac60091108c491dafb00877093170John Hoford float[] val = getFloats(s); 917abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, s.charAt(0), val); 918abb7d134c02ac60091108c491dafb00877093170John Hoford 919abb7d134c02ac60091108c491dafb00877093170John Hoford start = end; 920abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 921abb7d134c02ac60091108c491dafb00877093170John Hoford } 922abb7d134c02ac60091108c491dafb00877093170John Hoford if ((end - start) == 1 && start < value.length()) { 923abb7d134c02ac60091108c491dafb00877093170John Hoford 924abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, value.charAt(start), new float[0]); 925abb7d134c02ac60091108c491dafb00877093170John Hoford } 926abb7d134c02ac60091108c491dafb00877093170John Hoford return list.toArray(new VectorDrawable.VNode[list.size()]); 927abb7d134c02ac60091108c491dafb00877093170John Hoford } 928abb7d134c02ac60091108c491dafb00877093170John Hoford } 929abb7d134c02ac60091108c491dafb00877093170John Hoford 930abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VNode { 9315c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private char mType; 9325c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private float[] mParams; 9339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 934abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(char type, float[] params) { 9355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = type; 9365c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = params; 937abb7d134c02ac60091108c491dafb00877093170John Hoford } 938abb7d134c02ac60091108c491dafb00877093170John Hoford 939abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(VNode n) { 9405c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = n.mType; 9415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = Arrays.copyOf(n.mParams, n.mParams.length); 942abb7d134c02ac60091108c491dafb00877093170John Hoford } 943abb7d134c02ac60091108c491dafb00877093170John Hoford 944abb7d134c02ac60091108c491dafb00877093170John Hoford public static void createPath(VNode[] node, Path path) { 9455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette float[] current = new float[4]; 94633ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCommand = 'm'; 947abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < node.length; i++) { 94833ed52eff4b41f88858874e1af7723277a041b56ztenghui addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); 94933ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCommand = node[i].mType; 950abb7d134c02ac60091108c491dafb00877093170John Hoford } 951abb7d134c02ac60091108c491dafb00877093170John Hoford } 952abb7d134c02ac60091108c491dafb00877093170John Hoford 95333ed52eff4b41f88858874e1af7723277a041b56ztenghui private static void addCommand(Path path, float[] current, 95433ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCmd, char cmd, float[] val) { 955abb7d134c02ac60091108c491dafb00877093170John Hoford 956abb7d134c02ac60091108c491dafb00877093170John Hoford int incr = 2; 957abb7d134c02ac60091108c491dafb00877093170John Hoford float currentX = current[0]; 958abb7d134c02ac60091108c491dafb00877093170John Hoford float currentY = current[1]; 959abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointX = current[2]; 960abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointY = current[3]; 96133ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointX; 96233ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointY; 963abb7d134c02ac60091108c491dafb00877093170John Hoford 964abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 965abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': 966abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': 967abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 968abb7d134c02ac60091108c491dafb00877093170John Hoford return; 969abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': 970abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': 971abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': 972abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': 973abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': 974abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': 975abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 2; 976abb7d134c02ac60091108c491dafb00877093170John Hoford break; 977abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': 978abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': 979abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': 980abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': 981abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 1; 982abb7d134c02ac60091108c491dafb00877093170John Hoford break; 983abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': 984abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': 985abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 6; 986abb7d134c02ac60091108c491dafb00877093170John Hoford break; 987abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': 988abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': 989abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': 990abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': 991abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 4; 992abb7d134c02ac60091108c491dafb00877093170John Hoford break; 993abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': 994abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': 995abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 7; 996abb7d134c02ac60091108c491dafb00877093170John Hoford break; 997abb7d134c02ac60091108c491dafb00877093170John Hoford } 998abb7d134c02ac60091108c491dafb00877093170John Hoford for (int k = 0; k < val.length; k += incr) { 999abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 1000abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': // moveto - Start a new sub-path (relative) 1001abb7d134c02ac60091108c491dafb00877093170John Hoford path.rMoveTo(val[k + 0], val[k + 1]); 1002abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1003abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1004abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1005abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': // moveto - Start a new sub-path 1006abb7d134c02ac60091108c491dafb00877093170John Hoford path.moveTo(val[k + 0], val[k + 1]); 1007abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1008abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1009abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1010abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': // lineto - Draw a line from the current point (relative) 1011abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], val[k + 1]); 1012abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1013abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1014abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1015abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': // lineto - Draw a line from the current point 1016abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], val[k + 1]); 1017abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1018abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1019abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1020abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': // closepath - Close the current subpath 1021abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': // closepath - Close the current subpath 1022abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 1023abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1024abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': // horizontal lineto - Draws a horizontal line (relative) 1025abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], 0); 1026abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1027abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1028abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': // horizontal lineto - Draws a horizontal line 1029abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], currentY); 1030abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1031abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1032abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': // vertical lineto - Draws a vertical line from the current point (r) 1033abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(0, val[k + 0]); 1034abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 0]; 1035abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1036abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': // vertical lineto - Draws a vertical line from the current point 1037abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(currentX, val[k + 0]); 1038abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 0]; 1039abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1040abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': // curveto - Draws a cubic Bézier curve (relative) 104133ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 104233ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1043abb7d134c02ac60091108c491dafb00877093170John Hoford 1044abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 2]; 1045abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 3]; 1046abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 4]; 1047abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 5]; 1048abb7d134c02ac60091108c491dafb00877093170John Hoford 1049abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1050abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': // curveto - Draws a cubic Bézier curve 105133ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 105233ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1053abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 4]; 1054abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 5]; 1055abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 2]; 1056abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 3]; 1057abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1058abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) 105933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 106033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 106133ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 106233ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 106333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 106433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 106533ed52eff4b41f88858874e1af7723277a041b56ztenghui } 106633ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1067abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1], 1068abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], val[k + 3]); 1069abb7d134c02ac60091108c491dafb00877093170John Hoford 1070abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 0]; 1071abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 1]; 1072abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1073abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1074abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1075abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) 107633ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 107733ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 107833ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 107933ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 108033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 108133ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 108233ed52eff4b41f88858874e1af7723277a041b56ztenghui } 108333ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 108433ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1085abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1086abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 108733ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 108833ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1089abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1090abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': // Draws a quadratic Bézier (relative) 1091abb7d134c02ac60091108c491dafb00877093170John Hoford path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 109233ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = currentX + val[k + 0]; 109333ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = currentY + val[k + 1]; 1094abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1095abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1096abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1097abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': // Draws a quadratic Bézier 1098abb7d134c02ac60091108c491dafb00877093170John Hoford path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1099abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1100abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 110133ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 110233ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1103abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1104abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) 110533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 110633ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 110733ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 110833ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 110933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 111033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 111133ed52eff4b41f88858874e1af7723277a041b56ztenghui } 111233ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1113abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 1114175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointX = currentX + reflectiveCtrlPointX; 1115175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointY = currentY + reflectiveCtrlPointY; 1116abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1117abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1118abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1119abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': // Draws a quadratic Bézier curve (reflective control point) 112033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 112133ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 112233ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 112333ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 112433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 112533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 112633ed52eff4b41f88858874e1af7723277a041b56ztenghui } 112733ed52eff4b41f88858874e1af7723277a041b56ztenghui path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1128abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 112933ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = reflectiveCtrlPointX; 113033ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = reflectiveCtrlPointY; 1131abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 113233ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 1]; 1133abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1134abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': // Draws an elliptical arc 1135abb7d134c02ac60091108c491dafb00877093170John Hoford // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 1136abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1137abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1138abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1139abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5] + currentX, 1140abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6] + currentY, 1141abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1142abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1143abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1144abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1145abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1146abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 5]; 1147abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 6]; 1148abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1149abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1150abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1151abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': // Draws an elliptical arc 1152abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1153abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1154abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1155abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5], 1156abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6], 1157abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1158abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1159abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1160abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1161abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1162abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 5]; 1163abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 6]; 1164abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1165abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1166abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1167abb7d134c02ac60091108c491dafb00877093170John Hoford } 116833ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCmd = cmd; 1169abb7d134c02ac60091108c491dafb00877093170John Hoford } 1170abb7d134c02ac60091108c491dafb00877093170John Hoford current[0] = currentX; 1171abb7d134c02ac60091108c491dafb00877093170John Hoford current[1] = currentY; 1172abb7d134c02ac60091108c491dafb00877093170John Hoford current[2] = ctrlPointX; 1173abb7d134c02ac60091108c491dafb00877093170John Hoford current[3] = ctrlPointY; 1174abb7d134c02ac60091108c491dafb00877093170John Hoford } 1175abb7d134c02ac60091108c491dafb00877093170John Hoford 1176abb7d134c02ac60091108c491dafb00877093170John Hoford private static void drawArc(Path p, 1177abb7d134c02ac60091108c491dafb00877093170John Hoford float x0, 1178abb7d134c02ac60091108c491dafb00877093170John Hoford float y0, 1179abb7d134c02ac60091108c491dafb00877093170John Hoford float x1, 1180abb7d134c02ac60091108c491dafb00877093170John Hoford float y1, 1181abb7d134c02ac60091108c491dafb00877093170John Hoford float a, 1182abb7d134c02ac60091108c491dafb00877093170John Hoford float b, 1183abb7d134c02ac60091108c491dafb00877093170John Hoford float theta, 1184abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isMoreThanHalf, 1185abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isPositiveArc) { 1186abb7d134c02ac60091108c491dafb00877093170John Hoford 1187abb7d134c02ac60091108c491dafb00877093170John Hoford /* Convert rotation angle from degrees to radians */ 1188abb7d134c02ac60091108c491dafb00877093170John Hoford double thetaD = Math.toRadians(theta); 1189abb7d134c02ac60091108c491dafb00877093170John Hoford /* Pre-compute rotation matrix entries */ 1190abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(thetaD); 1191abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(thetaD); 1192abb7d134c02ac60091108c491dafb00877093170John Hoford /* Transform (x0, y0) and (x1, y1) into unit space */ 1193abb7d134c02ac60091108c491dafb00877093170John Hoford /* using (inverse) rotation, followed by (inverse) scale */ 1194abb7d134c02ac60091108c491dafb00877093170John Hoford double x0p = (x0 * cosTheta + y0 * sinTheta) / a; 1195abb7d134c02ac60091108c491dafb00877093170John Hoford double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; 1196abb7d134c02ac60091108c491dafb00877093170John Hoford double x1p = (x1 * cosTheta + y1 * sinTheta) / a; 1197abb7d134c02ac60091108c491dafb00877093170John Hoford double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; 1198abb7d134c02ac60091108c491dafb00877093170John Hoford 1199abb7d134c02ac60091108c491dafb00877093170John Hoford /* Compute differences and averages */ 1200abb7d134c02ac60091108c491dafb00877093170John Hoford double dx = x0p - x1p; 1201abb7d134c02ac60091108c491dafb00877093170John Hoford double dy = y0p - y1p; 1202abb7d134c02ac60091108c491dafb00877093170John Hoford double xm = (x0p + x1p) / 2; 1203abb7d134c02ac60091108c491dafb00877093170John Hoford double ym = (y0p + y1p) / 2; 1204abb7d134c02ac60091108c491dafb00877093170John Hoford /* Solve for intersecting unit circles */ 1205abb7d134c02ac60091108c491dafb00877093170John Hoford double dsq = dx * dx + dy * dy; 1206abb7d134c02ac60091108c491dafb00877093170John Hoford if (dsq == 0.0) { 1207abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, " Points are coincident"); 1208abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are coincident */ 1209abb7d134c02ac60091108c491dafb00877093170John Hoford } 1210abb7d134c02ac60091108c491dafb00877093170John Hoford double disc = 1.0 / dsq - 1.0 / 4.0; 1211abb7d134c02ac60091108c491dafb00877093170John Hoford if (disc < 0.0) { 1212abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, "Points are too far apart " + dsq); 1213abb7d134c02ac60091108c491dafb00877093170John Hoford float adjust = (float) (Math.sqrt(dsq) / 1.99999); 1214abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(p, x0, y0, x1, y1, a * adjust, 1215abb7d134c02ac60091108c491dafb00877093170John Hoford b * adjust, theta, isMoreThanHalf, isPositiveArc); 1216abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are too far apart */ 1217abb7d134c02ac60091108c491dafb00877093170John Hoford } 1218abb7d134c02ac60091108c491dafb00877093170John Hoford double s = Math.sqrt(disc); 1219abb7d134c02ac60091108c491dafb00877093170John Hoford double sdx = s * dx; 1220abb7d134c02ac60091108c491dafb00877093170John Hoford double sdy = s * dy; 1221abb7d134c02ac60091108c491dafb00877093170John Hoford double cx; 1222abb7d134c02ac60091108c491dafb00877093170John Hoford double cy; 1223abb7d134c02ac60091108c491dafb00877093170John Hoford if (isMoreThanHalf == isPositiveArc) { 1224abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm - sdy; 1225abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym + sdx; 1226abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1227abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm + sdy; 1228abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym - sdx; 1229abb7d134c02ac60091108c491dafb00877093170John Hoford } 1230abb7d134c02ac60091108c491dafb00877093170John Hoford 1231abb7d134c02ac60091108c491dafb00877093170John Hoford double eta0 = Math.atan2((y0p - cy), (x0p - cx)); 1232abb7d134c02ac60091108c491dafb00877093170John Hoford 1233abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = Math.atan2((y1p - cy), (x1p - cx)); 1234abb7d134c02ac60091108c491dafb00877093170John Hoford 1235abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep = (eta1 - eta0); 1236abb7d134c02ac60091108c491dafb00877093170John Hoford if (isPositiveArc != (sweep >= 0)) { 1237abb7d134c02ac60091108c491dafb00877093170John Hoford if (sweep > 0) { 1238abb7d134c02ac60091108c491dafb00877093170John Hoford sweep -= 2 * Math.PI; 1239abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1240abb7d134c02ac60091108c491dafb00877093170John Hoford sweep += 2 * Math.PI; 1241abb7d134c02ac60091108c491dafb00877093170John Hoford } 1242abb7d134c02ac60091108c491dafb00877093170John Hoford } 1243abb7d134c02ac60091108c491dafb00877093170John Hoford 1244abb7d134c02ac60091108c491dafb00877093170John Hoford cx *= a; 1245abb7d134c02ac60091108c491dafb00877093170John Hoford cy *= b; 1246abb7d134c02ac60091108c491dafb00877093170John Hoford double tcx = cx; 1247abb7d134c02ac60091108c491dafb00877093170John Hoford cx = cx * cosTheta - cy * sinTheta; 1248abb7d134c02ac60091108c491dafb00877093170John Hoford cy = tcx * sinTheta + cy * cosTheta; 1249abb7d134c02ac60091108c491dafb00877093170John Hoford 1250abb7d134c02ac60091108c491dafb00877093170John Hoford arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); 1251abb7d134c02ac60091108c491dafb00877093170John Hoford } 1252abb7d134c02ac60091108c491dafb00877093170John Hoford 1253abb7d134c02ac60091108c491dafb00877093170John Hoford /** 1254abb7d134c02ac60091108c491dafb00877093170John Hoford * Converts an arc to cubic Bezier segments and records them in p. 1255abb7d134c02ac60091108c491dafb00877093170John Hoford * 1256abb7d134c02ac60091108c491dafb00877093170John Hoford * @param p The target for the cubic Bezier segments 1257abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cx The x coordinate center of the ellipse 1258abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cy The y coordinate center of the ellipse 1259abb7d134c02ac60091108c491dafb00877093170John Hoford * @param a The radius of the ellipse in the horizontal direction 1260abb7d134c02ac60091108c491dafb00877093170John Hoford * @param b The radius of the ellipse in the vertical direction 1261abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1x E(eta1) x coordinate of the starting point of the arc 1262abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1y E(eta2) y coordinate of the starting point of the arc 1263abb7d134c02ac60091108c491dafb00877093170John Hoford * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane 1264abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start The start angle of the arc on the ellipse 1265abb7d134c02ac60091108c491dafb00877093170John Hoford * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse 1266abb7d134c02ac60091108c491dafb00877093170John Hoford */ 1267abb7d134c02ac60091108c491dafb00877093170John Hoford private static void arcToBezier(Path p, 1268abb7d134c02ac60091108c491dafb00877093170John Hoford double cx, 1269abb7d134c02ac60091108c491dafb00877093170John Hoford double cy, 1270abb7d134c02ac60091108c491dafb00877093170John Hoford double a, 1271abb7d134c02ac60091108c491dafb00877093170John Hoford double b, 1272abb7d134c02ac60091108c491dafb00877093170John Hoford double e1x, 1273abb7d134c02ac60091108c491dafb00877093170John Hoford double e1y, 1274abb7d134c02ac60091108c491dafb00877093170John Hoford double theta, 1275abb7d134c02ac60091108c491dafb00877093170John Hoford double start, 1276abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep) { 1277abb7d134c02ac60091108c491dafb00877093170John Hoford // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html 1278abb7d134c02ac60091108c491dafb00877093170John Hoford // and http://www.spaceroots.org/documents/ellipse/node22.html 1279abb7d134c02ac60091108c491dafb00877093170John Hoford 1280abb7d134c02ac60091108c491dafb00877093170John Hoford // Maximum of 45 degrees per cubic Bezier segment 1281abb7d134c02ac60091108c491dafb00877093170John Hoford int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); 1282abb7d134c02ac60091108c491dafb00877093170John Hoford 1283abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = start; 1284abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(theta); 1285abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(theta); 1286abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta1 = Math.cos(eta1); 1287abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta1 = Math.sin(eta1); 1288abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); 1289abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); 1290abb7d134c02ac60091108c491dafb00877093170John Hoford 1291abb7d134c02ac60091108c491dafb00877093170John Hoford double anglePerSegment = sweep / numSegments; 1292abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < numSegments; i++) { 1293abb7d134c02ac60091108c491dafb00877093170John Hoford double eta2 = eta1 + anglePerSegment; 1294abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta2 = Math.sin(eta2); 1295abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta2 = Math.cos(eta2); 1296abb7d134c02ac60091108c491dafb00877093170John Hoford double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); 1297abb7d134c02ac60091108c491dafb00877093170John Hoford double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); 1298abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; 1299abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; 1300abb7d134c02ac60091108c491dafb00877093170John Hoford double tanDiff2 = Math.tan((eta2 - eta1) / 2); 1301abb7d134c02ac60091108c491dafb00877093170John Hoford double alpha = 1302abb7d134c02ac60091108c491dafb00877093170John Hoford Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; 1303abb7d134c02ac60091108c491dafb00877093170John Hoford double q1x = e1x + alpha * ep1x; 1304abb7d134c02ac60091108c491dafb00877093170John Hoford double q1y = e1y + alpha * ep1y; 1305abb7d134c02ac60091108c491dafb00877093170John Hoford double q2x = e2x - alpha * ep2x; 1306abb7d134c02ac60091108c491dafb00877093170John Hoford double q2y = e2y - alpha * ep2y; 1307abb7d134c02ac60091108c491dafb00877093170John Hoford 1308abb7d134c02ac60091108c491dafb00877093170John Hoford p.cubicTo((float) q1x, 1309abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q1y, 1310abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2x, 1311abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2y, 1312abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2x, 1313abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2y); 1314abb7d134c02ac60091108c491dafb00877093170John Hoford eta1 = eta2; 1315abb7d134c02ac60091108c491dafb00877093170John Hoford e1x = e2x; 1316abb7d134c02ac60091108c491dafb00877093170John Hoford e1y = e2y; 1317abb7d134c02ac60091108c491dafb00877093170John Hoford ep1x = ep2x; 1318abb7d134c02ac60091108c491dafb00877093170John Hoford ep1y = ep2y; 1319abb7d134c02ac60091108c491dafb00877093170John Hoford } 1320abb7d134c02ac60091108c491dafb00877093170John Hoford } 1321abb7d134c02ac60091108c491dafb00877093170John Hoford 1322abb7d134c02ac60091108c491dafb00877093170John Hoford } 1323abb7d134c02ac60091108c491dafb00877093170John Hoford} 1324