VectorDrawable.java revision ddbbb8ae8561c9e61becd03faa40997d76ab5a51
1abb7d134c02ac60091108c491dafb00877093170John Hoford/* 2abb7d134c02ac60091108c491dafb00877093170John Hoford * Copyright (C) 2014 The Android Open Source Project 3abb7d134c02ac60091108c491dafb00877093170John Hoford * 4abb7d134c02ac60091108c491dafb00877093170John Hoford * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5abb7d134c02ac60091108c491dafb00877093170John Hoford * in compliance with the License. You may obtain a copy of the License at 6abb7d134c02ac60091108c491dafb00877093170John Hoford * 7abb7d134c02ac60091108c491dafb00877093170John Hoford * http://www.apache.org/licenses/LICENSE-2.0 8abb7d134c02ac60091108c491dafb00877093170John Hoford * 9abb7d134c02ac60091108c491dafb00877093170John Hoford * Unless required by applicable law or agreed to in writing, software distributed under the License 10abb7d134c02ac60091108c491dafb00877093170John Hoford * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11abb7d134c02ac60091108c491dafb00877093170John Hoford * or implied. See the License for the specific language governing permissions and limitations under 12abb7d134c02ac60091108c491dafb00877093170John Hoford * the License. 13abb7d134c02ac60091108c491dafb00877093170John Hoford */ 14abb7d134c02ac60091108c491dafb00877093170John Hoford 15abb7d134c02ac60091108c491dafb00877093170John Hofordpackage android.graphics.drawable; 16abb7d134c02ac60091108c491dafb00877093170John Hoford 17abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources; 18abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.content.res.Resources.Theme; 194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viveretteimport android.content.res.TypedArray; 20abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Canvas; 21abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.ColorFilter; 22abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Matrix; 23abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Paint; 24abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Path; 25abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PathMeasure; 26abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.PixelFormat; 27abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Rect; 28abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.graphics.Region; 29abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.AttributeSet; 30abb7d134c02ac60091108c491dafb00877093170John Hofordimport android.util.Log; 314b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport android.util.Xml; 32abb7d134c02ac60091108c491dafb00877093170John Hoford 33abb7d134c02ac60091108c491dafb00877093170John Hofordimport com.android.internal.R; 34abb7d134c02ac60091108c491dafb00877093170John Hoford 35abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParser; 36abb7d134c02ac60091108c491dafb00877093170John Hofordimport org.xmlpull.v1.XmlPullParserException; 374b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viveretteimport org.xmlpull.v1.XmlPullParserFactory; 38abb7d134c02ac60091108c491dafb00877093170John Hoford 39abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.io.IOException; 40abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.ArrayList; 41abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Arrays; 42abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.Collection; 43abb7d134c02ac60091108c491dafb00877093170John Hofordimport java.util.HashMap; 444b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 45abb7d134c02ac60091108c491dafb00877093170John Hoford/** 46d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * This lets you create a drawable based on an XML vector graphic It can be 47d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * defined in an XML file with the <code><vector></code> element. 48abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/> 49abb7d134c02ac60091108c491dafb00877093170John Hoford * The vector drawable has 6 elements: 50abb7d134c02ac60091108c491dafb00877093170John Hoford * <p/> 51abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl> 52177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui * <dt><code><vector></code></dt> 53fba3bad3870d607ecaed4f147788885c841c2ab3ztenghui * <dd>The attribute <code>android:versionCode</code> defines the version of 54d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * VectorDrawable</dd> 55abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><size></code></dt> 56abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the intrinsic Width Height size of the drawable using 57d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:width</code> and <code>android:height</code></dd> 58abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><viewport></code></dt> 59abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Used to defined the size of the virtual canvas the paths are drawn on. 60d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * The size is defined using the attributes <code>android:viewportHeight</code> 61d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <code>android:viewportWidth</code></dd> 62abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><group></code></dt> 63ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui * <dd>Defines the static 2D image.</dd> 64abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code><path></code></dt> 65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines paths to be drawn. The path elements must be within a group 66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl> 67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code> 68abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt> 69abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code> 70abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines path string.</dd></dt> 71abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fill</code> 72abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the color to fill the path (none if not present).</dd></dt> 73abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:stroke</code> 74d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Defines the color to draw the path outline (none if not present).</dd> 75d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * </dt> 76abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeWidth</code> 77abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The width a path stroke</dd></dt> 78abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeOpacity</code> 79abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity of a path stroke</dd></dt> 80abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:rotation</code> 81abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The amount to rotation the path stroke.</dd></dt> 82abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotX</code> 83abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The X coordinate of the center of rotation of a path</dd></dt> 84abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pivotY</code> 85abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The Y coordinate of the center of rotation of a path</dd></dt> 86abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:fillOpacity</code> 87abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The opacity to fill the path with</dd></dt> 88abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathStart</code> 89abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the start from 0 to 1</dd></dt> 90abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathEnd</code> 91abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>The fraction of the path to trim from the end from 0 to 1</dd></dt> 92abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:trimPathOffset</code> 93d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * <dd>Shift trim region (allows showed region to include the start and end) 94d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * from 0 to 1</dd></dt> 95abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:clipToPath</code> 96abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Path will set the clip path</dd></dt> 97abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineCap</code> 98abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the linecap for a stroked path: butt, round, square</dd></dt> 99abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeLineJoin</code> 100abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt> 101abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:strokeMiterLimit</code> 102abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Sets the Miter limit for a stroked path</dd></dt> 103abb7d134c02ac60091108c491dafb00877093170John Hoford * </dl> 104abb7d134c02ac60091108c491dafb00877093170John Hoford * </dd> 105abb7d134c02ac60091108c491dafb00877093170John Hoford */ 106abb7d134c02ac60091108c491dafb00877093170John Hofordpublic class VectorDrawable extends Drawable { 1079453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private static final String LOGTAG = VectorDrawable.class.getSimpleName(); 1089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 109abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_SIZE = "size"; 110abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_VIEWPORT = "viewport"; 111abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_GROUP = "group"; 112abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_PATH = "path"; 113abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_VECTOR = "vector"; 114abb7d134c02ac60091108c491dafb00877093170John Hoford 115abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_BUTT = 0; 116abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_ROUND = 1; 117abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_SQUARE = 2; 1189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 119abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_MITER = 0; 120abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_ROUND = 1; 121abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_BEVEL = 2; 1229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final VectorDrawableState mVectorState; 1244b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 125abb7d134c02ac60091108c491dafb00877093170John Hoford private int mAlpha = 0xFF; 126abb7d134c02ac60091108c491dafb00877093170John Hoford 127abb7d134c02ac60091108c491dafb00877093170John Hoford public VectorDrawable() { 1289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mVectorState = new VectorDrawableState(null); 129abb7d134c02ac60091108c491dafb00877093170John Hoford } 130abb7d134c02ac60091108c491dafb00877093170John Hoford 1319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) { 132abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState = new VectorDrawableState(state); 1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (theme != null && canApplyTheme()) { 1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette applyTheme(theme); 1369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 137abb7d134c02ac60091108c491dafb00877093170John Hoford } 138abb7d134c02ac60091108c491dafb00877093170John Hoford 139abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 140abb7d134c02ac60091108c491dafb00877093170John Hoford public ConstantState getConstantState() { 141abb7d134c02ac60091108c491dafb00877093170John Hoford return mVectorState; 142abb7d134c02ac60091108c491dafb00877093170John Hoford } 143abb7d134c02ac60091108c491dafb00877093170John Hoford 1444554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette @Override 145abb7d134c02ac60091108c491dafb00877093170John Hoford public void draw(Canvas canvas) { 1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final int saveCount = canvas.save(); 1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Rect bounds = getBounds(); 1484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.translate(bounds.left, bounds.top); 149ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); 1504b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.restoreToCount(saveCount); 151abb7d134c02ac60091108c491dafb00877093170John Hoford } 152abb7d134c02ac60091108c491dafb00877093170John Hoford 153abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 154abb7d134c02ac60091108c491dafb00877093170John Hoford public void setAlpha(int alpha) { 155abb7d134c02ac60091108c491dafb00877093170John Hoford // TODO correct handling of transparent 156abb7d134c02ac60091108c491dafb00877093170John Hoford if (mAlpha != alpha) { 157abb7d134c02ac60091108c491dafb00877093170John Hoford mAlpha = alpha; 158abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 159abb7d134c02ac60091108c491dafb00877093170John Hoford } 160abb7d134c02ac60091108c491dafb00877093170John Hoford } 161abb7d134c02ac60091108c491dafb00877093170John Hoford 162abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 163abb7d134c02ac60091108c491dafb00877093170John Hoford public void setColorFilter(ColorFilter colorFilter) { 164abb7d134c02ac60091108c491dafb00877093170John Hoford // TODO: support color filter 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; 269abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noGroupTag = true; 270abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noPathTag = true; 2719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette VGroup currentGroup = null; 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; 289abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_GROUP.equals(tagName)) { 2909453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette currentGroup = new VGroup(); 291ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.mGroupList.add(currentGroup); 292abb7d134c02ac60091108c491dafb00877093170John Hoford noGroupTag = false; 293d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette } else if (SHAPE_VECTOR.equals(tagName)) { 2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable); 295177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui 296177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui // Parsing the version information. 297177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui // Right now, we only support version "1". 298d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette // If the xml didn't specify the version number, the default 299d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette // version is "1". 3009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1); 301177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui if (versionCode != 1) { 302177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui throw new IllegalArgumentException( 303177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui "So far, VectorDrawable only support version 1"); 304177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui } 305177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui 306abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 307abb7d134c02ac60091108c491dafb00877093170John Hoford } 308abb7d134c02ac60091108c491dafb00877093170John Hoford } 3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 310abb7d134c02ac60091108c491dafb00877093170John Hoford eventType = parser.next(); 311abb7d134c02ac60091108c491dafb00877093170John Hoford } 3129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 313abb7d134c02ac60091108c491dafb00877093170John Hoford if (noSizeTag || noViewportTag || noGroupTag || noPathTag) { 3149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final StringBuffer tag = new StringBuffer(); 3159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 316abb7d134c02ac60091108c491dafb00877093170John Hoford if (noSizeTag) { 3179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 318abb7d134c02ac60091108c491dafb00877093170John Hoford } 3199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 320d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noViewportTag) { 321d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 322abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" & "); 323abb7d134c02ac60091108c491dafb00877093170John Hoford } 3249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 325abb7d134c02ac60091108c491dafb00877093170John Hoford } 3269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 327d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noGroupTag) { 328d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 329abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" & "); 330abb7d134c02ac60091108c491dafb00877093170John Hoford } 3319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_GROUP); 332abb7d134c02ac60091108c491dafb00877093170John Hoford } 3339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 334d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noPathTag) { 335d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 336abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" or "); 337abb7d134c02ac60091108c491dafb00877093170John Hoford } 3389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_PATH); 339abb7d134c02ac60091108c491dafb00877093170John Hoford } 3409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette throw new XmlPullParserException("no " + tag + " defined"); 342abb7d134c02ac60091108c491dafb00877093170John Hoford } 3439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 344abb7d134c02ac60091108c491dafb00877093170John Hoford // post parse cleanup 345ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseFinish(); 346ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return pathRenderer; 347abb7d134c02ac60091108c491dafb00877093170John Hoford } 348abb7d134c02ac60091108c491dafb00877093170John Hoford 349ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private void setPathRenderer(VPathRenderer pathRenderer) { 350ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer = pathRenderer; 351abb7d134c02ac60091108c491dafb00877093170John Hoford } 352abb7d134c02ac60091108c491dafb00877093170John Hoford 3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private static class VectorDrawableState extends ConstantState { 3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette int mChangingConfigurations; 355ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui VPathRenderer mVPathRenderer; 3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette Rect mPadding; 3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public VectorDrawableState(VectorDrawableState copy) { 3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette if (copy != null) { 3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mChangingConfigurations = copy.mChangingConfigurations; 361ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); 3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mPadding = new Rect(copy.mPadding); 3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable() { 3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, null, null); 3695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res) { 3735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, null); 3745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3755c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3765c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3775c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res, Theme theme) { 3785c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, theme); 3795c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3805c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3815c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3825c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public int getChangingConfigurations() { 3835c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return mChangingConfigurations; 3845c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3855c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3865c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 387ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private static class VPathRenderer { 3884b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mPath = new Path(); 3894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mRenderPath = new Path(); 3904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Matrix mMatrix = new Matrix(); 3914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 392abb7d134c02ac60091108c491dafb00877093170John Hoford private VPath[] mCurrentPaths; 3934b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mStrokePaint; 3944b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mFillPaint; 395abb7d134c02ac60091108c491dafb00877093170John Hoford private PathMeasure mPathMeasure; 3964b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 3979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>(); 3989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 399abb7d134c02ac60091108c491dafb00877093170John Hoford float mBaseWidth = 1; 400abb7d134c02ac60091108c491dafb00877093170John Hoford float mBaseHeight = 1; 401abb7d134c02ac60091108c491dafb00877093170John Hoford float mViewportWidth; 402abb7d134c02ac60091108c491dafb00877093170John Hoford float mViewportHeight; 403abb7d134c02ac60091108c491dafb00877093170John Hoford 404ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer() { 405abb7d134c02ac60091108c491dafb00877093170John Hoford } 4069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 407ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer(VPathRenderer copy) { 4089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mGroupList.addAll(copy.mGroupList); 409abb7d134c02ac60091108c491dafb00877093170John Hoford if (copy.mCurrentPaths != null) { 410abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths = new VPath[copy.mCurrentPaths.length]; 411abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mCurrentPaths.length; i++) { 412abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]); 413abb7d134c02ac60091108c491dafb00877093170John Hoford } 414abb7d134c02ac60091108c491dafb00877093170John Hoford } 415abb7d134c02ac60091108c491dafb00877093170John Hoford 416abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseWidth = copy.mBaseWidth; 417abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseHeight = copy.mBaseHeight; 418abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportWidth = copy.mViewportHeight; 419abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportHeight = copy.mViewportHeight; 420abb7d134c02ac60091108c491dafb00877093170John Hoford } 421abb7d134c02ac60091108c491dafb00877093170John Hoford 4229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 4239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final ArrayList<VGroup> groups = mGroupList; 4249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette for (int i = groups.size() - 1; i >= 0; i--) { 4259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final ArrayList<VPath> paths = groups.get(i).mVGList; 4269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette for (int j = paths.size() - 1; j >= 0; j--) { 4279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VPath path = paths.get(j); 4289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (path.canApplyTheme()) { 4299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return true; 4309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 4349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return false; 4359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 4379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 4389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final ArrayList<VGroup> groups = mGroupList; 4399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette for (int i = groups.size() - 1; i >= 0; i--) { 4409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final ArrayList<VPath> paths = groups.get(i).mVGList; 4419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette for (int j = paths.size() - 1; j >= 0; j--) { 4429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VPath path = paths.get(j); 4439453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (path.canApplyTheme()) { 4449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.applyTheme(t); 4459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 449abb7d134c02ac60091108c491dafb00877093170John Hoford } 450abb7d134c02ac60091108c491dafb00877093170John Hoford 4514b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette public void draw(Canvas canvas, int w, int h) { 452abb7d134c02ac60091108c491dafb00877093170John Hoford if (mCurrentPaths == null) { 453abb7d134c02ac60091108c491dafb00877093170John Hoford Log.e(LOGTAG,"mCurrentPaths == null"); 454abb7d134c02ac60091108c491dafb00877093170John Hoford return; 455abb7d134c02ac60091108c491dafb00877093170John Hoford } 456abb7d134c02ac60091108c491dafb00877093170John Hoford 457abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mCurrentPaths.length; i++) { 458ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui if (mCurrentPaths[i] != null) { 459abb7d134c02ac60091108c491dafb00877093170John Hoford drawPath(mCurrentPaths[i], canvas, w, h); 460abb7d134c02ac60091108c491dafb00877093170John Hoford } 461abb7d134c02ac60091108c491dafb00877093170John Hoford } 462abb7d134c02ac60091108c491dafb00877093170John Hoford } 463abb7d134c02ac60091108c491dafb00877093170John Hoford 464abb7d134c02ac60091108c491dafb00877093170John Hoford private void drawPath(VPath vPath, Canvas canvas, int w, int h) { 4659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final float scale = Math.min(h / mViewportHeight, w / mViewportWidth); 466abb7d134c02ac60091108c491dafb00877093170John Hoford 467abb7d134c02ac60091108c491dafb00877093170John Hoford vPath.toPath(mPath); 4684b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Path path = mPath; 469abb7d134c02ac60091108c491dafb00877093170John Hoford 470abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { 471abb7d134c02ac60091108c491dafb00877093170John Hoford float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; 472abb7d134c02ac60091108c491dafb00877093170John Hoford float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f; 473abb7d134c02ac60091108c491dafb00877093170John Hoford 474abb7d134c02ac60091108c491dafb00877093170John Hoford if (mPathMeasure == null) { 475abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure = new PathMeasure(); 476abb7d134c02ac60091108c491dafb00877093170John Hoford } 477abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.setPath(mPath, false); 478abb7d134c02ac60091108c491dafb00877093170John Hoford 479abb7d134c02ac60091108c491dafb00877093170John Hoford float len = mPathMeasure.getLength(); 480abb7d134c02ac60091108c491dafb00877093170John Hoford start = start * len; 481abb7d134c02ac60091108c491dafb00877093170John Hoford end = end * len; 482abb7d134c02ac60091108c491dafb00877093170John Hoford path.reset(); 483abb7d134c02ac60091108c491dafb00877093170John Hoford if (start > end) { 484abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.getSegment(start, len, path, true); 485abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.getSegment(0f, end, path, true); 486abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 487abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.getSegment(start, end, path, true); 488abb7d134c02ac60091108c491dafb00877093170John Hoford } 489abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(0, 0); // fix bug in measure 490abb7d134c02ac60091108c491dafb00877093170John Hoford } 491abb7d134c02ac60091108c491dafb00877093170John Hoford 492abb7d134c02ac60091108c491dafb00877093170John Hoford mRenderPath.reset(); 493abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.reset(); 494abb7d134c02ac60091108c491dafb00877093170John Hoford 495abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY); 496abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f); 497abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f); 498abb7d134c02ac60091108c491dafb00877093170John Hoford 499abb7d134c02ac60091108c491dafb00877093170John Hoford mRenderPath.addPath(path, mMatrix); 500abb7d134c02ac60091108c491dafb00877093170John Hoford 501abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mClip) { 502abb7d134c02ac60091108c491dafb00877093170John Hoford canvas.clipPath(mRenderPath, Region.Op.REPLACE); 503abb7d134c02ac60091108c491dafb00877093170John Hoford } 5049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 505abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mFillColor != 0) { 5064b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette if (mFillPaint == null) { 5074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mFillPaint = new Paint(); 5084b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mFillPaint.setStyle(Paint.Style.FILL); 5094b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mFillPaint.setAntiAlias(true); 5104b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette } 5114b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 512abb7d134c02ac60091108c491dafb00877093170John Hoford mFillPaint.setColor(vPath.mFillColor); 513abb7d134c02ac60091108c491dafb00877093170John Hoford canvas.drawPath(mRenderPath, mFillPaint); 514abb7d134c02ac60091108c491dafb00877093170John Hoford } 5159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 516abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mStrokeColor != 0) { 5174b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette if (mStrokePaint == null) { 5184b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mStrokePaint = new Paint(); 5194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mStrokePaint.setStyle(Paint.Style.STROKE); 5204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mStrokePaint.setAntiAlias(true); 5214b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette } 5224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Paint strokePaint = mStrokePaint; 5247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (vPath.mStrokeLineJoin != null) { 5254b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); 526abb7d134c02ac60091108c491dafb00877093170John Hoford } 5274b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (vPath.mStrokeLineCap != null) { 5294b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeCap(vPath.mStrokeLineCap); 530abb7d134c02ac60091108c491dafb00877093170John Hoford } 5314b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5324b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); 5334b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setColor(vPath.mStrokeColor); 5344b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); 5354b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.drawPath(mRenderPath, strokePaint); 536abb7d134c02ac60091108c491dafb00877093170John Hoford } 537abb7d134c02ac60091108c491dafb00877093170John Hoford } 538abb7d134c02ac60091108c491dafb00877093170John Hoford 539abb7d134c02ac60091108c491dafb00877093170John Hoford /** 540abb7d134c02ac60091108c491dafb00877093170John Hoford * Build the "current" path based on the first group 541abb7d134c02ac60091108c491dafb00877093170John Hoford * TODO: improve memory use & performance or move to C++ 542abb7d134c02ac60091108c491dafb00877093170John Hoford */ 543abb7d134c02ac60091108c491dafb00877093170John Hoford public void parseFinish() { 5449453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final Collection<VPath> paths = mGroupList.get(0).getPaths(); 545abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths = paths.toArray(new VPath[paths.size()]); 546abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mCurrentPaths.length; i++) { 547abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths[i] = new VPath(mCurrentPaths[i]); 548abb7d134c02ac60091108c491dafb00877093170John Hoford } 549abb7d134c02ac60091108c491dafb00877093170John Hoford } 550abb7d134c02ac60091108c491dafb00877093170John Hoford 551abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseViewport(Resources r, AttributeSet attrs) 552abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 5534b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); 554abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0); 555abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0); 556abb7d134c02ac60091108c491dafb00877093170John Hoford if (mViewportWidth == 0 || mViewportHeight == 0) { 557abb7d134c02ac60091108c491dafb00877093170John Hoford throw new XmlPullParserException(a.getPositionDescription()+ 558abb7d134c02ac60091108c491dafb00877093170John Hoford "<viewport> tag requires viewportWidth & viewportHeight to be set"); 559abb7d134c02ac60091108c491dafb00877093170John Hoford } 560abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 561abb7d134c02ac60091108c491dafb00877093170John Hoford } 562abb7d134c02ac60091108c491dafb00877093170John Hoford 563abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseSize(Resources r, AttributeSet attrs) 564abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 5654b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); 566abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0); 567abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0); 568abb7d134c02ac60091108c491dafb00877093170John Hoford if (mBaseWidth == 0 || mBaseHeight == 0) { 569abb7d134c02ac60091108c491dafb00877093170John Hoford throw new XmlPullParserException(a.getPositionDescription()+ 570abb7d134c02ac60091108c491dafb00877093170John Hoford "<size> tag requires width & height to be set"); 571abb7d134c02ac60091108c491dafb00877093170John Hoford } 572abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 573abb7d134c02ac60091108c491dafb00877093170John Hoford } 5744b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 575abb7d134c02ac60091108c491dafb00877093170John Hoford } 576abb7d134c02ac60091108c491dafb00877093170John Hoford 577abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VGroup { 5789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>(); 5799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private final ArrayList<VPath> mVGList = new ArrayList<VPath>(); 580abb7d134c02ac60091108c491dafb00877093170John Hoford 581abb7d134c02ac60091108c491dafb00877093170John Hoford public void add(VPath path) { 582abb7d134c02ac60091108c491dafb00877093170John Hoford String id = path.getID(); 583abb7d134c02ac60091108c491dafb00877093170John Hoford mVGPathMap.put(id, path); 584abb7d134c02ac60091108c491dafb00877093170John Hoford mVGList.add(path); 585abb7d134c02ac60091108c491dafb00877093170John Hoford } 586abb7d134c02ac60091108c491dafb00877093170John Hoford 587abb7d134c02ac60091108c491dafb00877093170John Hoford /** 588abb7d134c02ac60091108c491dafb00877093170John Hoford * Must return in order of adding 589abb7d134c02ac60091108c491dafb00877093170John Hoford * @return ordered list of paths 590abb7d134c02ac60091108c491dafb00877093170John Hoford */ 591abb7d134c02ac60091108c491dafb00877093170John Hoford public Collection<VPath> getPaths() { 592abb7d134c02ac60091108c491dafb00877093170John Hoford return mVGList; 593abb7d134c02ac60091108c491dafb00877093170John Hoford } 594abb7d134c02ac60091108c491dafb00877093170John Hoford 595abb7d134c02ac60091108c491dafb00877093170John Hoford } 596abb7d134c02ac60091108c491dafb00877093170John Hoford 597abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VPath { 598abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int MAX_STATES = 10; 5999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private int[] mThemeAttrs; 6019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 602abb7d134c02ac60091108c491dafb00877093170John Hoford int mStrokeColor = 0; 603abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeWidth = 0; 604abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeOpacity = Float.NaN; 6059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 606abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillColor = 0; 607abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillRule; 608abb7d134c02ac60091108c491dafb00877093170John Hoford float mFillOpacity = Float.NaN; 6099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 610abb7d134c02ac60091108c491dafb00877093170John Hoford float mRotate = 0; 611abb7d134c02ac60091108c491dafb00877093170John Hoford float mPivotX = 0; 612abb7d134c02ac60091108c491dafb00877093170John Hoford float mPivotY = 0; 6139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 614abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathStart = 0; 615abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathEnd = 1; 616abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathOffset = 0; 6179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 618abb7d134c02ac60091108c491dafb00877093170John Hoford boolean mClip = false; 6194b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; 6204b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Join mStrokeLineJoin = Paint.Join.MITER; 621abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeMiterlimit = 4; 6229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VNode[] mNode = null; 6249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private String mId; 625abb7d134c02ac60091108c491dafb00877093170John Hoford private int[] mCheckState = new int[MAX_STATES]; 626abb7d134c02ac60091108c491dafb00877093170John Hoford private boolean[] mCheckValue = new boolean[MAX_STATES]; 627abb7d134c02ac60091108c491dafb00877093170John Hoford private int mNumberOfStates = 0; 628abb7d134c02ac60091108c491dafb00877093170John Hoford 6299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public VPath() { 6309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette // Empty constructor. 6319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public VPath(VPath p) { 6349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette copyFrom(p); 6359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 637abb7d134c02ac60091108c491dafb00877093170John Hoford public void toPath(Path path) { 638abb7d134c02ac60091108c491dafb00877093170John Hoford path.reset(); 639abb7d134c02ac60091108c491dafb00877093170John Hoford if (mNode != null) { 640abb7d134c02ac60091108c491dafb00877093170John Hoford VNode.createPath(mNode, path); 641abb7d134c02ac60091108c491dafb00877093170John Hoford } 642abb7d134c02ac60091108c491dafb00877093170John Hoford } 643abb7d134c02ac60091108c491dafb00877093170John Hoford 6447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette public String getID() { 645abb7d134c02ac60091108c491dafb00877093170John Hoford return mId; 646abb7d134c02ac60091108c491dafb00877093170John Hoford } 647abb7d134c02ac60091108c491dafb00877093170John Hoford 6487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { 6497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 6507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_BUTT: 6517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.BUTT; 6527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_ROUND: 6537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.ROUND; 6547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_SQUARE: 6557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.SQUARE; 6567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 6577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 6587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) { 6627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 6637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_MITER: 6647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.MITER; 6657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_ROUND: 6667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.ROUND; 6677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_BEVEL: 6687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.BEVEL; 6697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 6707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 6717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void inflate(Resources r, AttributeSet attrs, Theme theme) { 6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath); 6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final int[] themeAttrs = a.extractThemeAttrs(); 6779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mThemeAttrs = themeAttrs; 6789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // NOTE: The set of attributes loaded here MUST match the 6807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // set of attributes loaded in applyTheme. 6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) { 6827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 6837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) { 6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mId = a.getString(R.styleable.VectorDrawablePath_name); 6877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) { 6907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 6917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 692abb7d134c02ac60091108c491dafb00877093170John Hoford 6939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) { 6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 6959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) { 6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 699abb7d134c02ac60091108c491dafb00877093170John Hoford } 7009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) { 7027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate); 7037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) { 7067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX); 707abb7d134c02ac60091108c491dafb00877093170John Hoford } 7089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) { 7107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY); 7117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7137f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7147f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) { 7157f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap( 7167f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 7177f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7197f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7207f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) { 7217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin( 7227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 723abb7d134c02ac60091108c491dafb00877093170John Hoford } 7249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) { 7277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 7287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) { 7329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 733abb7d134c02ac60091108c491dafb00877093170John Hoford } 7349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null 7369453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) { 7379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeOpacity = a.getFloat( 7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 7399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) { 7427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 7437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) { 7467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 7477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) { 7517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 7527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 7537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7547f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7557f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7567f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) { 7577f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 7587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 7597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7619453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 7629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 763abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 764abb7d134c02ac60091108c491dafb00877093170John Hoford } 765abb7d134c02ac60091108c491dafb00877093170John Hoford 7669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 7679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return mThemeAttrs != null; 7689453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7709453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 7719453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (mThemeAttrs == null) { 7729453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return; 7739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7749453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = t.resolveAttributes( 7769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0); 7779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 7799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_name)) { 7817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mId = a.getString(R.styleable.VectorDrawablePath_name); 7829453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7839453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) { 7857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 7869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7879453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 7897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 7907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate); 7927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX); 7937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY); 7947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap(a.getInt( 7967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 7977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin(a.getInt( 7987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 7997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 8007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 8017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 8027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeOpacity = a.getFloat( 8037f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 8047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 8057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 8067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 8077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 8087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 8097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 8107f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 8119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 8139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private void updateColorAlphas() { 8169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mFillOpacity)) { 8179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mFillColor &= 0x00FFFFFF; 8189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mFillColor |= ((int) (0xFF * mFillOpacity)) << 24; 8199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mStrokeOpacity)) { 8229453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor &= 0x00FFFFFF; 8239453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24; 8249453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 827abb7d134c02ac60091108c491dafb00877093170John Hoford private static int nextStart(String s, int end) { 828abb7d134c02ac60091108c491dafb00877093170John Hoford char c; 829abb7d134c02ac60091108c491dafb00877093170John Hoford 830abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < s.length()) { 831abb7d134c02ac60091108c491dafb00877093170John Hoford c = s.charAt(end); 832abb7d134c02ac60091108c491dafb00877093170John Hoford if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { 833abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 834abb7d134c02ac60091108c491dafb00877093170John Hoford } 835abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 836abb7d134c02ac60091108c491dafb00877093170John Hoford } 837abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 838abb7d134c02ac60091108c491dafb00877093170John Hoford } 839abb7d134c02ac60091108c491dafb00877093170John Hoford 840abb7d134c02ac60091108c491dafb00877093170John Hoford private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) { 841abb7d134c02ac60091108c491dafb00877093170John Hoford list.add(new VectorDrawable.VNode(cmd, val)); 842abb7d134c02ac60091108c491dafb00877093170John Hoford } 843abb7d134c02ac60091108c491dafb00877093170John Hoford 844abb7d134c02ac60091108c491dafb00877093170John Hoford /** 845abb7d134c02ac60091108c491dafb00877093170John Hoford * parse the floats in the string 846abb7d134c02ac60091108c491dafb00877093170John Hoford * this is an optimized version of 847abb7d134c02ac60091108c491dafb00877093170John Hoford * parseFloat(s.split(",|\\s")); 848abb7d134c02ac60091108c491dafb00877093170John Hoford * 849abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string containing a command and list of floats 850abb7d134c02ac60091108c491dafb00877093170John Hoford * @return array of floats 851abb7d134c02ac60091108c491dafb00877093170John Hoford */ 852abb7d134c02ac60091108c491dafb00877093170John Hoford private static float[] getFloats(String s) { 853abb7d134c02ac60091108c491dafb00877093170John Hoford if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { 854abb7d134c02ac60091108c491dafb00877093170John Hoford return new float[0]; 855abb7d134c02ac60091108c491dafb00877093170John Hoford } 856abb7d134c02ac60091108c491dafb00877093170John Hoford try { 857abb7d134c02ac60091108c491dafb00877093170John Hoford float[] tmp = new float[s.length()]; 858abb7d134c02ac60091108c491dafb00877093170John Hoford int count = 0; 859abb7d134c02ac60091108c491dafb00877093170John Hoford int pos = 1, end; 860abb7d134c02ac60091108c491dafb00877093170John Hoford while ((end = extract(s, pos)) >= 0) { 861abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < end) { 862abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, end)); 863abb7d134c02ac60091108c491dafb00877093170John Hoford } 864abb7d134c02ac60091108c491dafb00877093170John Hoford pos = end + 1; 865abb7d134c02ac60091108c491dafb00877093170John Hoford } 866abb7d134c02ac60091108c491dafb00877093170John Hoford // handle the final float if there is one 867abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < s.length()) { 868abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, s.length())); 869abb7d134c02ac60091108c491dafb00877093170John Hoford } 870abb7d134c02ac60091108c491dafb00877093170John Hoford return Arrays.copyOf(tmp, count); 871abb7d134c02ac60091108c491dafb00877093170John Hoford } catch (NumberFormatException e){ 872abb7d134c02ac60091108c491dafb00877093170John Hoford Log.e(LOGTAG,"error in parsing \""+s+"\""); 873abb7d134c02ac60091108c491dafb00877093170John Hoford throw e; 874abb7d134c02ac60091108c491dafb00877093170John Hoford } 875abb7d134c02ac60091108c491dafb00877093170John Hoford } 876abb7d134c02ac60091108c491dafb00877093170John Hoford 877abb7d134c02ac60091108c491dafb00877093170John Hoford /** 878abb7d134c02ac60091108c491dafb00877093170John Hoford * calculate the position of the next comma or space 879abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string to search 880abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start the position to start searching 881abb7d134c02ac60091108c491dafb00877093170John Hoford * @return the position of the next comma or space or -1 if none found 882abb7d134c02ac60091108c491dafb00877093170John Hoford */ 883abb7d134c02ac60091108c491dafb00877093170John Hoford private static int extract(String s, int start) { 884abb7d134c02ac60091108c491dafb00877093170John Hoford int space = s.indexOf(' ', start); 885abb7d134c02ac60091108c491dafb00877093170John Hoford int comma = s.indexOf(',', start); 886abb7d134c02ac60091108c491dafb00877093170John Hoford if (space == -1) { 887abb7d134c02ac60091108c491dafb00877093170John Hoford return comma; 888abb7d134c02ac60091108c491dafb00877093170John Hoford } 889abb7d134c02ac60091108c491dafb00877093170John Hoford if (comma == -1) { 890abb7d134c02ac60091108c491dafb00877093170John Hoford return space; 891abb7d134c02ac60091108c491dafb00877093170John Hoford } 892abb7d134c02ac60091108c491dafb00877093170John Hoford return (comma > space) ? space : comma; 893abb7d134c02ac60091108c491dafb00877093170John Hoford } 894abb7d134c02ac60091108c491dafb00877093170John Hoford 895abb7d134c02ac60091108c491dafb00877093170John Hoford private VectorDrawable.VNode[] parsePath(String value) { 896abb7d134c02ac60091108c491dafb00877093170John Hoford int start = 0; 897abb7d134c02ac60091108c491dafb00877093170John Hoford int end = 1; 898abb7d134c02ac60091108c491dafb00877093170John Hoford 899abb7d134c02ac60091108c491dafb00877093170John Hoford ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>(); 900abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < value.length()) { 901abb7d134c02ac60091108c491dafb00877093170John Hoford end = nextStart(value, end); 902abb7d134c02ac60091108c491dafb00877093170John Hoford String s = value.substring(start, end); 903abb7d134c02ac60091108c491dafb00877093170John Hoford float[] val = getFloats(s); 904abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, s.charAt(0), val); 905abb7d134c02ac60091108c491dafb00877093170John Hoford 906abb7d134c02ac60091108c491dafb00877093170John Hoford start = end; 907abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 908abb7d134c02ac60091108c491dafb00877093170John Hoford } 909abb7d134c02ac60091108c491dafb00877093170John Hoford if ((end - start) == 1 && start < value.length()) { 910abb7d134c02ac60091108c491dafb00877093170John Hoford 911abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, value.charAt(start), new float[0]); 912abb7d134c02ac60091108c491dafb00877093170John Hoford } 913abb7d134c02ac60091108c491dafb00877093170John Hoford return list.toArray(new VectorDrawable.VNode[list.size()]); 914abb7d134c02ac60091108c491dafb00877093170John Hoford } 915abb7d134c02ac60091108c491dafb00877093170John Hoford 916abb7d134c02ac60091108c491dafb00877093170John Hoford public void copyFrom(VPath p1) { 917abb7d134c02ac60091108c491dafb00877093170John Hoford mNode = new VNode[p1.mNode.length]; 918abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mNode.length; i++) { 919abb7d134c02ac60091108c491dafb00877093170John Hoford mNode[i] = new VNode(p1.mNode[i]); 920abb7d134c02ac60091108c491dafb00877093170John Hoford } 921abb7d134c02ac60091108c491dafb00877093170John Hoford mId = p1.mId; 922abb7d134c02ac60091108c491dafb00877093170John Hoford mStrokeColor = p1.mStrokeColor; 923abb7d134c02ac60091108c491dafb00877093170John Hoford mFillColor = p1.mFillColor; 924abb7d134c02ac60091108c491dafb00877093170John Hoford mStrokeWidth = p1.mStrokeWidth; 925abb7d134c02ac60091108c491dafb00877093170John Hoford mRotate = p1.mRotate; 926abb7d134c02ac60091108c491dafb00877093170John Hoford mPivotX = p1.mPivotX; 927abb7d134c02ac60091108c491dafb00877093170John Hoford mPivotY = p1.mPivotY; 928abb7d134c02ac60091108c491dafb00877093170John Hoford mTrimPathStart = p1.mTrimPathStart; 929abb7d134c02ac60091108c491dafb00877093170John Hoford mTrimPathEnd = p1.mTrimPathEnd; 930abb7d134c02ac60091108c491dafb00877093170John Hoford mTrimPathOffset = p1.mTrimPathOffset; 9317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = p1.mStrokeLineCap; 9327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = p1.mStrokeLineJoin; 933abb7d134c02ac60091108c491dafb00877093170John Hoford mStrokeMiterlimit = p1.mStrokeMiterlimit; 934abb7d134c02ac60091108c491dafb00877093170John Hoford mNumberOfStates = p1.mNumberOfStates; 935abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mNumberOfStates; i++) { 936abb7d134c02ac60091108c491dafb00877093170John Hoford mCheckState[i] = p1.mCheckState[i]; 937abb7d134c02ac60091108c491dafb00877093170John Hoford mCheckValue[i] = p1.mCheckValue[i]; 938abb7d134c02ac60091108c491dafb00877093170John Hoford } 939abb7d134c02ac60091108c491dafb00877093170John Hoford 940abb7d134c02ac60091108c491dafb00877093170John Hoford mFillRule = p1.mFillRule; 941abb7d134c02ac60091108c491dafb00877093170John Hoford } 942abb7d134c02ac60091108c491dafb00877093170John Hoford } 943abb7d134c02ac60091108c491dafb00877093170John Hoford 944abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VNode { 9455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private char mType; 9465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private float[] mParams; 9479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 948abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(char type, float[] params) { 9495c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = type; 9505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = params; 951abb7d134c02ac60091108c491dafb00877093170John Hoford } 952abb7d134c02ac60091108c491dafb00877093170John Hoford 953abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(VNode n) { 9545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = n.mType; 9555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = Arrays.copyOf(n.mParams, n.mParams.length); 956abb7d134c02ac60091108c491dafb00877093170John Hoford } 957abb7d134c02ac60091108c491dafb00877093170John Hoford 958abb7d134c02ac60091108c491dafb00877093170John Hoford public static void createPath(VNode[] node, Path path) { 9595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette float[] current = new float[4]; 96033ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCommand = 'm'; 961abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < node.length; i++) { 96233ed52eff4b41f88858874e1af7723277a041b56ztenghui addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); 96333ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCommand = node[i].mType; 964abb7d134c02ac60091108c491dafb00877093170John Hoford } 965abb7d134c02ac60091108c491dafb00877093170John Hoford } 966abb7d134c02ac60091108c491dafb00877093170John Hoford 96733ed52eff4b41f88858874e1af7723277a041b56ztenghui private static void addCommand(Path path, float[] current, 96833ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCmd, char cmd, float[] val) { 969abb7d134c02ac60091108c491dafb00877093170John Hoford 970abb7d134c02ac60091108c491dafb00877093170John Hoford int incr = 2; 971abb7d134c02ac60091108c491dafb00877093170John Hoford float currentX = current[0]; 972abb7d134c02ac60091108c491dafb00877093170John Hoford float currentY = current[1]; 973abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointX = current[2]; 974abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointY = current[3]; 97533ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointX; 97633ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointY; 977abb7d134c02ac60091108c491dafb00877093170John Hoford 978abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 979abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': 980abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': 981abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 982abb7d134c02ac60091108c491dafb00877093170John Hoford return; 983abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': 984abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': 985abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': 986abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': 987abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': 988abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': 989abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 2; 990abb7d134c02ac60091108c491dafb00877093170John Hoford break; 991abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': 992abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': 993abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': 994abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': 995abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 1; 996abb7d134c02ac60091108c491dafb00877093170John Hoford break; 997abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': 998abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': 999abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 6; 1000abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1001abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': 1002abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': 1003abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': 1004abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': 1005abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 4; 1006abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1007abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': 1008abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': 1009abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 7; 1010abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1011abb7d134c02ac60091108c491dafb00877093170John Hoford } 1012abb7d134c02ac60091108c491dafb00877093170John Hoford for (int k = 0; k < val.length; k += incr) { 1013abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 1014abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': // moveto - Start a new sub-path (relative) 1015abb7d134c02ac60091108c491dafb00877093170John Hoford path.rMoveTo(val[k + 0], val[k + 1]); 1016abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1017abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1018abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1019abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': // moveto - Start a new sub-path 1020abb7d134c02ac60091108c491dafb00877093170John Hoford path.moveTo(val[k + 0], val[k + 1]); 1021abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1022abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1023abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1024abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': // lineto - Draw a line from the current point (relative) 1025abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], val[k + 1]); 1026abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1027abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1028abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1029abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': // lineto - Draw a line from the current point 1030abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], val[k + 1]); 1031abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1032abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1033abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1034abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': // closepath - Close the current subpath 1035abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': // closepath - Close the current subpath 1036abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 1037abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1038abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': // horizontal lineto - Draws a horizontal line (relative) 1039abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], 0); 1040abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1041abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1042abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': // horizontal lineto - Draws a horizontal line 1043abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], currentY); 1044abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1045abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1046abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': // vertical lineto - Draws a vertical line from the current point (r) 1047abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(0, val[k + 0]); 1048abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 0]; 1049abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1050abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': // vertical lineto - Draws a vertical line from the current point 1051abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(currentX, val[k + 0]); 1052abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 0]; 1053abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1054abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': // curveto - Draws a cubic Bézier curve (relative) 105533ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 105633ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1057abb7d134c02ac60091108c491dafb00877093170John Hoford 1058abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 2]; 1059abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 3]; 1060abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 4]; 1061abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 5]; 1062abb7d134c02ac60091108c491dafb00877093170John Hoford 1063abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1064abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': // curveto - Draws a cubic Bézier curve 106533ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 106633ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1067abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 4]; 1068abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 5]; 1069abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 2]; 1070abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 3]; 1071abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1072abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) 107333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 107433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 107533ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 107633ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 107733ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 107833ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 107933ed52eff4b41f88858874e1af7723277a041b56ztenghui } 108033ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1081abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1], 1082abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], val[k + 3]); 1083abb7d134c02ac60091108c491dafb00877093170John Hoford 1084abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 0]; 1085abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 1]; 1086abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1087abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1088abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1089abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) 109033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 109133ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 109233ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 109333ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 109433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 109533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 109633ed52eff4b41f88858874e1af7723277a041b56ztenghui } 109733ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 109833ed52eff4b41f88858874e1af7723277a041b56ztenghui 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 'q': // Draws a quadratic Bézier (relative) 1105abb7d134c02ac60091108c491dafb00877093170John Hoford path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 110633ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = currentX + val[k + 0]; 110733ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = currentY + val[k + 1]; 1108abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1109abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1110abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1111abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': // Draws a quadratic Bézier 1112abb7d134c02ac60091108c491dafb00877093170John Hoford path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1113abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1114abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 111533ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 111633ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1117abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1118abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) 111933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 112033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 112133ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 112233ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 112333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 112433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 112533ed52eff4b41f88858874e1af7723277a041b56ztenghui } 112633ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1127abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 1128175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointX = currentX + reflectiveCtrlPointX; 1129175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointY = currentY + reflectiveCtrlPointY; 1130abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1131abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1132abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1133abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': // Draws a quadratic Bézier curve (reflective control point) 113433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 113533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 113633ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 113733ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 113833ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 113933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 114033ed52eff4b41f88858874e1af7723277a041b56ztenghui } 114133ed52eff4b41f88858874e1af7723277a041b56ztenghui path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1142abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 114333ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = reflectiveCtrlPointX; 114433ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = reflectiveCtrlPointY; 1145abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 114633ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 1]; 1147abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1148abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': // Draws an elliptical arc 1149abb7d134c02ac60091108c491dafb00877093170John Hoford // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 1150abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1151abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1152abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1153abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5] + currentX, 1154abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6] + currentY, 1155abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1156abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1157abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1158abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1159abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1160abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 5]; 1161abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 6]; 1162abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1163abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1164abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1165abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': // Draws an elliptical arc 1166abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1167abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1168abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1169abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5], 1170abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6], 1171abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1172abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1173abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1174abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1175abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1176abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 5]; 1177abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 6]; 1178abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1179abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1180abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1181abb7d134c02ac60091108c491dafb00877093170John Hoford } 118233ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCmd = cmd; 1183abb7d134c02ac60091108c491dafb00877093170John Hoford } 1184abb7d134c02ac60091108c491dafb00877093170John Hoford current[0] = currentX; 1185abb7d134c02ac60091108c491dafb00877093170John Hoford current[1] = currentY; 1186abb7d134c02ac60091108c491dafb00877093170John Hoford current[2] = ctrlPointX; 1187abb7d134c02ac60091108c491dafb00877093170John Hoford current[3] = ctrlPointY; 1188abb7d134c02ac60091108c491dafb00877093170John Hoford } 1189abb7d134c02ac60091108c491dafb00877093170John Hoford 1190abb7d134c02ac60091108c491dafb00877093170John Hoford private static void drawArc(Path p, 1191abb7d134c02ac60091108c491dafb00877093170John Hoford float x0, 1192abb7d134c02ac60091108c491dafb00877093170John Hoford float y0, 1193abb7d134c02ac60091108c491dafb00877093170John Hoford float x1, 1194abb7d134c02ac60091108c491dafb00877093170John Hoford float y1, 1195abb7d134c02ac60091108c491dafb00877093170John Hoford float a, 1196abb7d134c02ac60091108c491dafb00877093170John Hoford float b, 1197abb7d134c02ac60091108c491dafb00877093170John Hoford float theta, 1198abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isMoreThanHalf, 1199abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isPositiveArc) { 1200abb7d134c02ac60091108c491dafb00877093170John Hoford 1201abb7d134c02ac60091108c491dafb00877093170John Hoford /* Convert rotation angle from degrees to radians */ 1202abb7d134c02ac60091108c491dafb00877093170John Hoford double thetaD = Math.toRadians(theta); 1203abb7d134c02ac60091108c491dafb00877093170John Hoford /* Pre-compute rotation matrix entries */ 1204abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(thetaD); 1205abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(thetaD); 1206abb7d134c02ac60091108c491dafb00877093170John Hoford /* Transform (x0, y0) and (x1, y1) into unit space */ 1207abb7d134c02ac60091108c491dafb00877093170John Hoford /* using (inverse) rotation, followed by (inverse) scale */ 1208abb7d134c02ac60091108c491dafb00877093170John Hoford double x0p = (x0 * cosTheta + y0 * sinTheta) / a; 1209abb7d134c02ac60091108c491dafb00877093170John Hoford double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; 1210abb7d134c02ac60091108c491dafb00877093170John Hoford double x1p = (x1 * cosTheta + y1 * sinTheta) / a; 1211abb7d134c02ac60091108c491dafb00877093170John Hoford double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; 1212abb7d134c02ac60091108c491dafb00877093170John Hoford 1213abb7d134c02ac60091108c491dafb00877093170John Hoford /* Compute differences and averages */ 1214abb7d134c02ac60091108c491dafb00877093170John Hoford double dx = x0p - x1p; 1215abb7d134c02ac60091108c491dafb00877093170John Hoford double dy = y0p - y1p; 1216abb7d134c02ac60091108c491dafb00877093170John Hoford double xm = (x0p + x1p) / 2; 1217abb7d134c02ac60091108c491dafb00877093170John Hoford double ym = (y0p + y1p) / 2; 1218abb7d134c02ac60091108c491dafb00877093170John Hoford /* Solve for intersecting unit circles */ 1219abb7d134c02ac60091108c491dafb00877093170John Hoford double dsq = dx * dx + dy * dy; 1220abb7d134c02ac60091108c491dafb00877093170John Hoford if (dsq == 0.0) { 1221abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, " Points are coincident"); 1222abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are coincident */ 1223abb7d134c02ac60091108c491dafb00877093170John Hoford } 1224abb7d134c02ac60091108c491dafb00877093170John Hoford double disc = 1.0 / dsq - 1.0 / 4.0; 1225abb7d134c02ac60091108c491dafb00877093170John Hoford if (disc < 0.0) { 1226abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, "Points are too far apart " + dsq); 1227abb7d134c02ac60091108c491dafb00877093170John Hoford float adjust = (float) (Math.sqrt(dsq) / 1.99999); 1228abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(p, x0, y0, x1, y1, a * adjust, 1229abb7d134c02ac60091108c491dafb00877093170John Hoford b * adjust, theta, isMoreThanHalf, isPositiveArc); 1230abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are too far apart */ 1231abb7d134c02ac60091108c491dafb00877093170John Hoford } 1232abb7d134c02ac60091108c491dafb00877093170John Hoford double s = Math.sqrt(disc); 1233abb7d134c02ac60091108c491dafb00877093170John Hoford double sdx = s * dx; 1234abb7d134c02ac60091108c491dafb00877093170John Hoford double sdy = s * dy; 1235abb7d134c02ac60091108c491dafb00877093170John Hoford double cx; 1236abb7d134c02ac60091108c491dafb00877093170John Hoford double cy; 1237abb7d134c02ac60091108c491dafb00877093170John Hoford if (isMoreThanHalf == isPositiveArc) { 1238abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm - sdy; 1239abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym + sdx; 1240abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1241abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm + sdy; 1242abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym - sdx; 1243abb7d134c02ac60091108c491dafb00877093170John Hoford } 1244abb7d134c02ac60091108c491dafb00877093170John Hoford 1245abb7d134c02ac60091108c491dafb00877093170John Hoford double eta0 = Math.atan2((y0p - cy), (x0p - cx)); 1246abb7d134c02ac60091108c491dafb00877093170John Hoford 1247abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = Math.atan2((y1p - cy), (x1p - cx)); 1248abb7d134c02ac60091108c491dafb00877093170John Hoford 1249abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep = (eta1 - eta0); 1250abb7d134c02ac60091108c491dafb00877093170John Hoford if (isPositiveArc != (sweep >= 0)) { 1251abb7d134c02ac60091108c491dafb00877093170John Hoford if (sweep > 0) { 1252abb7d134c02ac60091108c491dafb00877093170John Hoford sweep -= 2 * Math.PI; 1253abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1254abb7d134c02ac60091108c491dafb00877093170John Hoford sweep += 2 * Math.PI; 1255abb7d134c02ac60091108c491dafb00877093170John Hoford } 1256abb7d134c02ac60091108c491dafb00877093170John Hoford } 1257abb7d134c02ac60091108c491dafb00877093170John Hoford 1258abb7d134c02ac60091108c491dafb00877093170John Hoford cx *= a; 1259abb7d134c02ac60091108c491dafb00877093170John Hoford cy *= b; 1260abb7d134c02ac60091108c491dafb00877093170John Hoford double tcx = cx; 1261abb7d134c02ac60091108c491dafb00877093170John Hoford cx = cx * cosTheta - cy * sinTheta; 1262abb7d134c02ac60091108c491dafb00877093170John Hoford cy = tcx * sinTheta + cy * cosTheta; 1263abb7d134c02ac60091108c491dafb00877093170John Hoford 1264abb7d134c02ac60091108c491dafb00877093170John Hoford arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); 1265abb7d134c02ac60091108c491dafb00877093170John Hoford } 1266abb7d134c02ac60091108c491dafb00877093170John Hoford 1267abb7d134c02ac60091108c491dafb00877093170John Hoford /** 1268abb7d134c02ac60091108c491dafb00877093170John Hoford * Converts an arc to cubic Bezier segments and records them in p. 1269abb7d134c02ac60091108c491dafb00877093170John Hoford * 1270abb7d134c02ac60091108c491dafb00877093170John Hoford * @param p The target for the cubic Bezier segments 1271abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cx The x coordinate center of the ellipse 1272abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cy The y coordinate center of the ellipse 1273abb7d134c02ac60091108c491dafb00877093170John Hoford * @param a The radius of the ellipse in the horizontal direction 1274abb7d134c02ac60091108c491dafb00877093170John Hoford * @param b The radius of the ellipse in the vertical direction 1275abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1x E(eta1) x coordinate of the starting point of the arc 1276abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1y E(eta2) y coordinate of the starting point of the arc 1277abb7d134c02ac60091108c491dafb00877093170John Hoford * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane 1278abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start The start angle of the arc on the ellipse 1279abb7d134c02ac60091108c491dafb00877093170John Hoford * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse 1280abb7d134c02ac60091108c491dafb00877093170John Hoford */ 1281abb7d134c02ac60091108c491dafb00877093170John Hoford private static void arcToBezier(Path p, 1282abb7d134c02ac60091108c491dafb00877093170John Hoford double cx, 1283abb7d134c02ac60091108c491dafb00877093170John Hoford double cy, 1284abb7d134c02ac60091108c491dafb00877093170John Hoford double a, 1285abb7d134c02ac60091108c491dafb00877093170John Hoford double b, 1286abb7d134c02ac60091108c491dafb00877093170John Hoford double e1x, 1287abb7d134c02ac60091108c491dafb00877093170John Hoford double e1y, 1288abb7d134c02ac60091108c491dafb00877093170John Hoford double theta, 1289abb7d134c02ac60091108c491dafb00877093170John Hoford double start, 1290abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep) { 1291abb7d134c02ac60091108c491dafb00877093170John Hoford // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html 1292abb7d134c02ac60091108c491dafb00877093170John Hoford // and http://www.spaceroots.org/documents/ellipse/node22.html 1293abb7d134c02ac60091108c491dafb00877093170John Hoford 1294abb7d134c02ac60091108c491dafb00877093170John Hoford // Maximum of 45 degrees per cubic Bezier segment 1295abb7d134c02ac60091108c491dafb00877093170John Hoford int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); 1296abb7d134c02ac60091108c491dafb00877093170John Hoford 1297abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = start; 1298abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(theta); 1299abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(theta); 1300abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta1 = Math.cos(eta1); 1301abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta1 = Math.sin(eta1); 1302abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); 1303abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); 1304abb7d134c02ac60091108c491dafb00877093170John Hoford 1305abb7d134c02ac60091108c491dafb00877093170John Hoford double anglePerSegment = sweep / numSegments; 1306abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < numSegments; i++) { 1307abb7d134c02ac60091108c491dafb00877093170John Hoford double eta2 = eta1 + anglePerSegment; 1308abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta2 = Math.sin(eta2); 1309abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta2 = Math.cos(eta2); 1310abb7d134c02ac60091108c491dafb00877093170John Hoford double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); 1311abb7d134c02ac60091108c491dafb00877093170John Hoford double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); 1312abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; 1313abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; 1314abb7d134c02ac60091108c491dafb00877093170John Hoford double tanDiff2 = Math.tan((eta2 - eta1) / 2); 1315abb7d134c02ac60091108c491dafb00877093170John Hoford double alpha = 1316abb7d134c02ac60091108c491dafb00877093170John Hoford Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; 1317abb7d134c02ac60091108c491dafb00877093170John Hoford double q1x = e1x + alpha * ep1x; 1318abb7d134c02ac60091108c491dafb00877093170John Hoford double q1y = e1y + alpha * ep1y; 1319abb7d134c02ac60091108c491dafb00877093170John Hoford double q2x = e2x - alpha * ep2x; 1320abb7d134c02ac60091108c491dafb00877093170John Hoford double q2y = e2y - alpha * ep2y; 1321abb7d134c02ac60091108c491dafb00877093170John Hoford 1322abb7d134c02ac60091108c491dafb00877093170John Hoford p.cubicTo((float) q1x, 1323abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q1y, 1324abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2x, 1325abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2y, 1326abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2x, 1327abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2y); 1328abb7d134c02ac60091108c491dafb00877093170John Hoford eta1 = eta2; 1329abb7d134c02ac60091108c491dafb00877093170John Hoford e1x = e2x; 1330abb7d134c02ac60091108c491dafb00877093170John Hoford e1y = e2y; 1331abb7d134c02ac60091108c491dafb00877093170John Hoford ep1x = ep2x; 1332abb7d134c02ac60091108c491dafb00877093170John Hoford ep1y = ep2y; 1333abb7d134c02ac60091108c491dafb00877093170John Hoford } 1334abb7d134c02ac60091108c491dafb00877093170John Hoford } 1335abb7d134c02ac60091108c491dafb00877093170John Hoford 1336abb7d134c02ac60091108c491dafb00877093170John Hoford } 1337abb7d134c02ac60091108c491dafb00877093170John Hoford} 1338