VectorDrawable.java revision 46e546c28fd52b4dedf0a0fbd313db589cb9048b
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/> 4946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The vector drawable has the following 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><path></code></dt> 6346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines paths to be drawn. Multiple paths can be defined in one xml file. 6446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * The paths are drawn in the order of their definition order. 65abb7d134c02ac60091108c491dafb00877093170John Hoford * <dl> 66abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:name</code> 67abb7d134c02ac60091108c491dafb00877093170John Hoford * <dd>Defines the name of the path.</dd></dt> 68abb7d134c02ac60091108c491dafb00877093170John Hoford * <dt><code>android:pathData</code> 6946e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * <dd>Defines path string. This is using exactly same format as "d" attribute 7046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * in the SVG's path data</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_PATH = "path"; 112abb7d134c02ac60091108c491dafb00877093170John Hoford private static final String SHAPE_VECTOR = "vector"; 113abb7d134c02ac60091108c491dafb00877093170John Hoford 114abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_BUTT = 0; 115abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_ROUND = 1; 116abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINECAP_SQUARE = 2; 1179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 118abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_MITER = 0; 119abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_ROUND = 1; 120abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int LINEJOIN_BEVEL = 2; 1219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1224b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final VectorDrawableState mVectorState; 1234b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 124abb7d134c02ac60091108c491dafb00877093170John Hoford private int mAlpha = 0xFF; 125abb7d134c02ac60091108c491dafb00877093170John Hoford 126abb7d134c02ac60091108c491dafb00877093170John Hoford public VectorDrawable() { 1279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mVectorState = new VectorDrawableState(null); 128abb7d134c02ac60091108c491dafb00877093170John Hoford } 129abb7d134c02ac60091108c491dafb00877093170John Hoford 1309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) { 131abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState = new VectorDrawableState(state); 1329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 1339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (theme != null && canApplyTheme()) { 1349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette applyTheme(theme); 1359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 136abb7d134c02ac60091108c491dafb00877093170John Hoford } 137abb7d134c02ac60091108c491dafb00877093170John Hoford 138abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 139abb7d134c02ac60091108c491dafb00877093170John Hoford public ConstantState getConstantState() { 140abb7d134c02ac60091108c491dafb00877093170John Hoford return mVectorState; 141abb7d134c02ac60091108c491dafb00877093170John Hoford } 142abb7d134c02ac60091108c491dafb00877093170John Hoford 1434554a6a5137d8e9bdfb623ad84ff344a48b7eb9dAlan Viverette @Override 144abb7d134c02ac60091108c491dafb00877093170John Hoford public void draw(Canvas canvas) { 1454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final int saveCount = canvas.save(); 1464b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Rect bounds = getBounds(); 1474b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.translate(bounds.left, bounds.top); 148ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height()); 1494b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.restoreToCount(saveCount); 150abb7d134c02ac60091108c491dafb00877093170John Hoford } 151abb7d134c02ac60091108c491dafb00877093170John Hoford 152abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 153abb7d134c02ac60091108c491dafb00877093170John Hoford public void setAlpha(int alpha) { 154abb7d134c02ac60091108c491dafb00877093170John Hoford // TODO correct handling of transparent 155abb7d134c02ac60091108c491dafb00877093170John Hoford if (mAlpha != alpha) { 156abb7d134c02ac60091108c491dafb00877093170John Hoford mAlpha = alpha; 157abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 158abb7d134c02ac60091108c491dafb00877093170John Hoford } 159abb7d134c02ac60091108c491dafb00877093170John Hoford } 160abb7d134c02ac60091108c491dafb00877093170John Hoford 161abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 162abb7d134c02ac60091108c491dafb00877093170John Hoford public void setColorFilter(ColorFilter colorFilter) { 163abb7d134c02ac60091108c491dafb00877093170John Hoford // TODO: support color filter 164abb7d134c02ac60091108c491dafb00877093170John Hoford } 165abb7d134c02ac60091108c491dafb00877093170John Hoford 166abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 167abb7d134c02ac60091108c491dafb00877093170John Hoford public int getOpacity() { 168abb7d134c02ac60091108c491dafb00877093170John Hoford return PixelFormat.TRANSLUCENT; 169abb7d134c02ac60091108c491dafb00877093170John Hoford } 170abb7d134c02ac60091108c491dafb00877093170John Hoford 171abb7d134c02ac60091108c491dafb00877093170John Hoford /** 172d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * Sets padding for this shape, defined by a Rect object. Define the padding 173d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette * in the Rect object as: left, top, right, bottom. 174abb7d134c02ac60091108c491dafb00877093170John Hoford */ 175abb7d134c02ac60091108c491dafb00877093170John Hoford public void setPadding(Rect padding) { 176abb7d134c02ac60091108c491dafb00877093170John Hoford setPadding(padding.left, padding.top, padding.right, padding.bottom); 177abb7d134c02ac60091108c491dafb00877093170John Hoford } 178abb7d134c02ac60091108c491dafb00877093170John Hoford 179abb7d134c02ac60091108c491dafb00877093170John Hoford /** 180abb7d134c02ac60091108c491dafb00877093170John Hoford * Sets padding for the shape. 181abb7d134c02ac60091108c491dafb00877093170John Hoford * 182abb7d134c02ac60091108c491dafb00877093170John Hoford * @param left padding for the left side (in pixels) 183abb7d134c02ac60091108c491dafb00877093170John Hoford * @param top padding for the top (in pixels) 184abb7d134c02ac60091108c491dafb00877093170John Hoford * @param right padding for the right side (in pixels) 185abb7d134c02ac60091108c491dafb00877093170John Hoford * @param bottom padding for the bottom (in pixels) 186abb7d134c02ac60091108c491dafb00877093170John Hoford */ 187abb7d134c02ac60091108c491dafb00877093170John Hoford public void setPadding(int left, int top, int right, int bottom) { 188abb7d134c02ac60091108c491dafb00877093170John Hoford if ((left | top | right | bottom) == 0) { 189abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding = null; 190abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 191abb7d134c02ac60091108c491dafb00877093170John Hoford if (mVectorState.mPadding == null) { 192abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding = new Rect(); 193abb7d134c02ac60091108c491dafb00877093170John Hoford } 194abb7d134c02ac60091108c491dafb00877093170John Hoford mVectorState.mPadding.set(left, top, right, bottom); 195abb7d134c02ac60091108c491dafb00877093170John Hoford } 196abb7d134c02ac60091108c491dafb00877093170John Hoford invalidateSelf(); 197abb7d134c02ac60091108c491dafb00877093170John Hoford } 198abb7d134c02ac60091108c491dafb00877093170John Hoford 199abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 200abb7d134c02ac60091108c491dafb00877093170John Hoford public int getIntrinsicWidth() { 201ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return (int) mVectorState.mVPathRenderer.mBaseWidth; 202abb7d134c02ac60091108c491dafb00877093170John Hoford } 203abb7d134c02ac60091108c491dafb00877093170John Hoford 204abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 205abb7d134c02ac60091108c491dafb00877093170John Hoford public int getIntrinsicHeight() { 206ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return (int) mVectorState.mVPathRenderer.mBaseHeight; 207abb7d134c02ac60091108c491dafb00877093170John Hoford } 208abb7d134c02ac60091108c491dafb00877093170John Hoford 209abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 210abb7d134c02ac60091108c491dafb00877093170John Hoford public boolean getPadding(Rect padding) { 211abb7d134c02ac60091108c491dafb00877093170John Hoford if (mVectorState.mPadding != null) { 212abb7d134c02ac60091108c491dafb00877093170John Hoford padding.set(mVectorState.mPadding); 213abb7d134c02ac60091108c491dafb00877093170John Hoford return true; 214abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 215abb7d134c02ac60091108c491dafb00877093170John Hoford return super.getPadding(padding); 216abb7d134c02ac60091108c491dafb00877093170John Hoford } 217abb7d134c02ac60091108c491dafb00877093170John Hoford } 218abb7d134c02ac60091108c491dafb00877093170John Hoford 219abb7d134c02ac60091108c491dafb00877093170John Hoford @Override 220abb7d134c02ac60091108c491dafb00877093170John Hoford public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) 221abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException, IOException { 222ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer p = inflateInternal(res, parser, attrs, theme); 223ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui setPathRenderer(p); 224abb7d134c02ac60091108c491dafb00877093170John Hoford } 225abb7d134c02ac60091108c491dafb00877093170John Hoford 2269453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette @Override 2279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 2289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme(); 2299453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2319453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette @Override 2329453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 2339453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette super.applyTheme(t); 2349453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2359453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VectorDrawableState state = mVectorState; 236ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer path = state.mVPathRenderer; 2379453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (path != null && path.canApplyTheme()) { 2389453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.applyTheme(t); 2399453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2409453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 2419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 2424b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette /** @hide */ 2434b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette public static VectorDrawable create(Resources resources, int rid) { 2444b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette try { 2454b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final XmlPullParser xpp = resources.getXml(rid); 2464b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final AttributeSet attrs = Xml.asAttributeSet(xpp); 2474b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 2484b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette factory.setNamespaceAware(true); 2494b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 2504b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette final VectorDrawable drawable = new VectorDrawable(); 2514b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette drawable.inflate(resources, xpp, attrs); 2524b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 2534b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette return drawable; 2544b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } catch (XmlPullParserException e) { 2554b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette Log.e(LOGTAG, "parser error", e); 2564b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } catch (IOException e) { 2574b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette Log.e(LOGTAG, "parser error", e); 2584b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } 2594b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette return null; 2604b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette } 2614b1a7c203d5e32c8b2dc7f4f54f28559ca31860aAlan Viverette 262ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, 2639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette Theme theme) throws XmlPullParserException, IOException { 264ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui final VPathRenderer pathRenderer = new VPathRenderer(); 2659453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 266abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noSizeTag = true; 267abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noViewportTag = true; 268abb7d134c02ac60091108c491dafb00877093170John Hoford boolean noPathTag = true; 2699453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 27046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui VGroup currentGroup = new VGroup(); 271abb7d134c02ac60091108c491dafb00877093170John Hoford 272abb7d134c02ac60091108c491dafb00877093170John Hoford int eventType = parser.getEventType(); 273abb7d134c02ac60091108c491dafb00877093170John Hoford while (eventType != XmlPullParser.END_DOCUMENT) { 274abb7d134c02ac60091108c491dafb00877093170John Hoford if (eventType == XmlPullParser.START_TAG) { 2759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final String tagName = parser.getName(); 276abb7d134c02ac60091108c491dafb00877093170John Hoford if (SHAPE_PATH.equals(tagName)) { 2779453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final VPath path = new VPath(); 2789453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette path.inflate(res, attrs, theme); 2799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette currentGroup.add(path); 280abb7d134c02ac60091108c491dafb00877093170John Hoford noPathTag = false; 281abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_SIZE.equals(tagName)) { 282ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseSize(res, attrs); 283abb7d134c02ac60091108c491dafb00877093170John Hoford noSizeTag = false; 284abb7d134c02ac60091108c491dafb00877093170John Hoford } else if (SHAPE_VIEWPORT.equals(tagName)) { 285ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseViewport(res, attrs); 286abb7d134c02ac60091108c491dafb00877093170John Hoford noViewportTag = false; 287d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette } else if (SHAPE_VECTOR.equals(tagName)) { 2889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable); 289177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui 290177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui // Parsing the version information. 291177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui // Right now, we only support version "1". 292d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette // If the xml didn't specify the version number, the default 293d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette // version is "1". 2949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1); 295177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui if (versionCode != 1) { 296177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui throw new IllegalArgumentException( 297177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui "So far, VectorDrawable only support version 1"); 298177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui } 299177dffd869ff1f5bdf816faead01a7dc4980bf75ztenghui 300abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 301abb7d134c02ac60091108c491dafb00877093170John Hoford } 302abb7d134c02ac60091108c491dafb00877093170John Hoford } 3039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 304abb7d134c02ac60091108c491dafb00877093170John Hoford eventType = parser.next(); 305abb7d134c02ac60091108c491dafb00877093170John Hoford } 3069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 30746e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui if (noSizeTag || noViewportTag || noPathTag) { 3089453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final StringBuffer tag = new StringBuffer(); 3099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 310abb7d134c02ac60091108c491dafb00877093170John Hoford if (noSizeTag) { 3119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 312abb7d134c02ac60091108c491dafb00877093170John Hoford } 3139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 314d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noViewportTag) { 315d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 316abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" & "); 317abb7d134c02ac60091108c491dafb00877093170John Hoford } 3189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_SIZE); 319abb7d134c02ac60091108c491dafb00877093170John Hoford } 3209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 321d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (noPathTag) { 322d20974bd51852c71114b6e0e4ffdc3613a4d90aaAlan Viverette if (tag.length() > 0) { 323abb7d134c02ac60091108c491dafb00877093170John Hoford tag.append(" or "); 324abb7d134c02ac60091108c491dafb00877093170John Hoford } 3259453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette tag.append(SHAPE_PATH); 326abb7d134c02ac60091108c491dafb00877093170John Hoford } 3279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 3289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette throw new XmlPullParserException("no " + tag + " defined"); 329abb7d134c02ac60091108c491dafb00877093170John Hoford } 3309453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 33146e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui pathRenderer.mCurrentGroup = currentGroup; 332abb7d134c02ac60091108c491dafb00877093170John Hoford // post parse cleanup 333ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui pathRenderer.parseFinish(); 334ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui return pathRenderer; 335abb7d134c02ac60091108c491dafb00877093170John Hoford } 336abb7d134c02ac60091108c491dafb00877093170John Hoford 337ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private void setPathRenderer(VPathRenderer pathRenderer) { 338ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVectorState.mVPathRenderer = pathRenderer; 339abb7d134c02ac60091108c491dafb00877093170John Hoford } 340abb7d134c02ac60091108c491dafb00877093170John Hoford 3415c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private static class VectorDrawableState extends ConstantState { 3425c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette int mChangingConfigurations; 343ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui VPathRenderer mVPathRenderer; 3445c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette Rect mPadding; 3455c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3465c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public VectorDrawableState(VectorDrawableState copy) { 3475c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette if (copy != null) { 3485c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mChangingConfigurations = copy.mChangingConfigurations; 349ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); 3505c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mPadding = new Rect(copy.mPadding); 3515c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3525c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3535c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3545c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3555c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable() { 3565c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, null, null); 3575c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3585c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3595c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3605c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res) { 3615c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, null); 3625c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3635c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3645c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3655c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public Drawable newDrawable(Resources res, Theme theme) { 3665c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return new VectorDrawable(this, res, theme); 3675c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3685c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 3695c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette @Override 3705c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette public int getChangingConfigurations() { 3715c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette return mChangingConfigurations; 3725c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3735c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette } 3745c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette 375ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui private static class VPathRenderer { 3764b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mPath = new Path(); 3774b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Path mRenderPath = new Path(); 3784b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private final Matrix mMatrix = new Matrix(); 3794b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 380abb7d134c02ac60091108c491dafb00877093170John Hoford private VPath[] mCurrentPaths; 3814b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mStrokePaint; 3824b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette private Paint mFillPaint; 383abb7d134c02ac60091108c491dafb00877093170John Hoford private PathMeasure mPathMeasure; 3844b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 38546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui private VGroup mCurrentGroup = new VGroup(); 3869453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 387abb7d134c02ac60091108c491dafb00877093170John Hoford float mBaseWidth = 1; 388abb7d134c02ac60091108c491dafb00877093170John Hoford float mBaseHeight = 1; 389abb7d134c02ac60091108c491dafb00877093170John Hoford float mViewportWidth; 390abb7d134c02ac60091108c491dafb00877093170John Hoford float mViewportHeight; 391abb7d134c02ac60091108c491dafb00877093170John Hoford 392ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer() { 393abb7d134c02ac60091108c491dafb00877093170John Hoford } 3949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 395ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui public VPathRenderer(VPathRenderer copy) { 39646e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui mCurrentGroup = copy.mCurrentGroup; 397abb7d134c02ac60091108c491dafb00877093170John Hoford if (copy.mCurrentPaths != null) { 398abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths = new VPath[copy.mCurrentPaths.length]; 399abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mCurrentPaths.length; i++) { 400abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]); 401abb7d134c02ac60091108c491dafb00877093170John Hoford } 402abb7d134c02ac60091108c491dafb00877093170John Hoford } 403abb7d134c02ac60091108c491dafb00877093170John Hoford 404abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseWidth = copy.mBaseWidth; 405abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseHeight = copy.mBaseHeight; 406abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportWidth = copy.mViewportHeight; 407abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportHeight = copy.mViewportHeight; 408abb7d134c02ac60091108c491dafb00877093170John Hoford } 409abb7d134c02ac60091108c491dafb00877093170John Hoford 4109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 41146e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui final ArrayList<VPath> paths = mCurrentGroup.mVGList; 41246e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui for (int j = paths.size() - 1; j >= 0; j--) { 41346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui final VPath path = paths.get(j); 41446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui if (path.canApplyTheme()) { 41546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui return true; 4169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4189453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return false; 4199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 4219453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 42246e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui final ArrayList<VPath> paths = mCurrentGroup.mVGList; 42346e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui for (int j = paths.size() - 1; j >= 0; j--) { 42446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui final VPath path = paths.get(j); 42546e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui if (path.canApplyTheme()) { 42646e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui path.applyTheme(t); 4279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 4289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 429abb7d134c02ac60091108c491dafb00877093170John Hoford } 430abb7d134c02ac60091108c491dafb00877093170John Hoford 4314b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette public void draw(Canvas canvas, int w, int h) { 432abb7d134c02ac60091108c491dafb00877093170John Hoford if (mCurrentPaths == null) { 433abb7d134c02ac60091108c491dafb00877093170John Hoford Log.e(LOGTAG,"mCurrentPaths == null"); 434abb7d134c02ac60091108c491dafb00877093170John Hoford return; 435abb7d134c02ac60091108c491dafb00877093170John Hoford } 436abb7d134c02ac60091108c491dafb00877093170John Hoford 437abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mCurrentPaths.length; i++) { 438ddbbb8ae8561c9e61becd03faa40997d76ab5a51ztenghui if (mCurrentPaths[i] != null) { 439abb7d134c02ac60091108c491dafb00877093170John Hoford drawPath(mCurrentPaths[i], canvas, w, h); 440abb7d134c02ac60091108c491dafb00877093170John Hoford } 441abb7d134c02ac60091108c491dafb00877093170John Hoford } 442abb7d134c02ac60091108c491dafb00877093170John Hoford } 443abb7d134c02ac60091108c491dafb00877093170John Hoford 444abb7d134c02ac60091108c491dafb00877093170John Hoford private void drawPath(VPath vPath, Canvas canvas, int w, int h) { 4459453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final float scale = Math.min(h / mViewportHeight, w / mViewportWidth); 446abb7d134c02ac60091108c491dafb00877093170John Hoford 447abb7d134c02ac60091108c491dafb00877093170John Hoford vPath.toPath(mPath); 4484b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Path path = mPath; 449abb7d134c02ac60091108c491dafb00877093170John Hoford 450abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { 451abb7d134c02ac60091108c491dafb00877093170John Hoford float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; 452abb7d134c02ac60091108c491dafb00877093170John Hoford float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f; 453abb7d134c02ac60091108c491dafb00877093170John Hoford 454abb7d134c02ac60091108c491dafb00877093170John Hoford if (mPathMeasure == null) { 455abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure = new PathMeasure(); 456abb7d134c02ac60091108c491dafb00877093170John Hoford } 457abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.setPath(mPath, false); 458abb7d134c02ac60091108c491dafb00877093170John Hoford 459abb7d134c02ac60091108c491dafb00877093170John Hoford float len = mPathMeasure.getLength(); 460abb7d134c02ac60091108c491dafb00877093170John Hoford start = start * len; 461abb7d134c02ac60091108c491dafb00877093170John Hoford end = end * len; 462abb7d134c02ac60091108c491dafb00877093170John Hoford path.reset(); 463abb7d134c02ac60091108c491dafb00877093170John Hoford if (start > end) { 464abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.getSegment(start, len, path, true); 465abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.getSegment(0f, end, path, true); 466abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 467abb7d134c02ac60091108c491dafb00877093170John Hoford mPathMeasure.getSegment(start, end, path, true); 468abb7d134c02ac60091108c491dafb00877093170John Hoford } 469abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(0, 0); // fix bug in measure 470abb7d134c02ac60091108c491dafb00877093170John Hoford } 471abb7d134c02ac60091108c491dafb00877093170John Hoford 472abb7d134c02ac60091108c491dafb00877093170John Hoford mRenderPath.reset(); 473abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.reset(); 474abb7d134c02ac60091108c491dafb00877093170John Hoford 475abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY); 476abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f); 477abb7d134c02ac60091108c491dafb00877093170John Hoford mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f); 478abb7d134c02ac60091108c491dafb00877093170John Hoford 479abb7d134c02ac60091108c491dafb00877093170John Hoford mRenderPath.addPath(path, mMatrix); 480abb7d134c02ac60091108c491dafb00877093170John Hoford 481abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mClip) { 482abb7d134c02ac60091108c491dafb00877093170John Hoford canvas.clipPath(mRenderPath, Region.Op.REPLACE); 483abb7d134c02ac60091108c491dafb00877093170John Hoford } 4849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 485abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mFillColor != 0) { 4864b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette if (mFillPaint == null) { 4874b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mFillPaint = new Paint(); 4884b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mFillPaint.setStyle(Paint.Style.FILL); 4894b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mFillPaint.setAntiAlias(true); 4904b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette } 4914b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 492abb7d134c02ac60091108c491dafb00877093170John Hoford mFillPaint.setColor(vPath.mFillColor); 493abb7d134c02ac60091108c491dafb00877093170John Hoford canvas.drawPath(mRenderPath, mFillPaint); 494abb7d134c02ac60091108c491dafb00877093170John Hoford } 4959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 496abb7d134c02ac60091108c491dafb00877093170John Hoford if (vPath.mStrokeColor != 0) { 4974b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette if (mStrokePaint == null) { 4984b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mStrokePaint = new Paint(); 4994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mStrokePaint.setStyle(Paint.Style.STROKE); 5004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette mStrokePaint.setAntiAlias(true); 5014b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette } 5024b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5034b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final Paint strokePaint = mStrokePaint; 5047f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (vPath.mStrokeLineJoin != null) { 5054b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); 506abb7d134c02ac60091108c491dafb00877093170John Hoford } 5074b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (vPath.mStrokeLineCap != null) { 5094b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeCap(vPath.mStrokeLineCap); 510abb7d134c02ac60091108c491dafb00877093170John Hoford } 5114b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 5124b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); 5134b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setColor(vPath.mStrokeColor); 5144b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); 5154b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette canvas.drawPath(mRenderPath, strokePaint); 516abb7d134c02ac60091108c491dafb00877093170John Hoford } 517abb7d134c02ac60091108c491dafb00877093170John Hoford } 518abb7d134c02ac60091108c491dafb00877093170John Hoford 519abb7d134c02ac60091108c491dafb00877093170John Hoford /** 52046e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui * Build the "current" path based on the current group 521abb7d134c02ac60091108c491dafb00877093170John Hoford * TODO: improve memory use & performance or move to C++ 522abb7d134c02ac60091108c491dafb00877093170John Hoford */ 523abb7d134c02ac60091108c491dafb00877093170John Hoford public void parseFinish() { 52446e546c28fd52b4dedf0a0fbd313db589cb9048bztenghui final Collection<VPath> paths = mCurrentGroup.getPaths(); 525abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths = paths.toArray(new VPath[paths.size()]); 526abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mCurrentPaths.length; i++) { 527abb7d134c02ac60091108c491dafb00877093170John Hoford mCurrentPaths[i] = new VPath(mCurrentPaths[i]); 528abb7d134c02ac60091108c491dafb00877093170John Hoford } 529abb7d134c02ac60091108c491dafb00877093170John Hoford } 530abb7d134c02ac60091108c491dafb00877093170John Hoford 531abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseViewport(Resources r, AttributeSet attrs) 532abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 5334b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); 534abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0); 535abb7d134c02ac60091108c491dafb00877093170John Hoford mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0); 536abb7d134c02ac60091108c491dafb00877093170John Hoford if (mViewportWidth == 0 || mViewportHeight == 0) { 537abb7d134c02ac60091108c491dafb00877093170John Hoford throw new XmlPullParserException(a.getPositionDescription()+ 538abb7d134c02ac60091108c491dafb00877093170John Hoford "<viewport> tag requires viewportWidth & viewportHeight to be set"); 539abb7d134c02ac60091108c491dafb00877093170John Hoford } 540abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 541abb7d134c02ac60091108c491dafb00877093170John Hoford } 542abb7d134c02ac60091108c491dafb00877093170John Hoford 543abb7d134c02ac60091108c491dafb00877093170John Hoford private void parseSize(Resources r, AttributeSet attrs) 544abb7d134c02ac60091108c491dafb00877093170John Hoford throws XmlPullParserException { 5454b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); 546abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0); 547abb7d134c02ac60091108c491dafb00877093170John Hoford mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0); 548abb7d134c02ac60091108c491dafb00877093170John Hoford if (mBaseWidth == 0 || mBaseHeight == 0) { 549abb7d134c02ac60091108c491dafb00877093170John Hoford throw new XmlPullParserException(a.getPositionDescription()+ 550abb7d134c02ac60091108c491dafb00877093170John Hoford "<size> tag requires width & height to be set"); 551abb7d134c02ac60091108c491dafb00877093170John Hoford } 552abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 553abb7d134c02ac60091108c491dafb00877093170John Hoford } 5544b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette 555abb7d134c02ac60091108c491dafb00877093170John Hoford } 556abb7d134c02ac60091108c491dafb00877093170John Hoford 557abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VGroup { 5589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>(); 5599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private final ArrayList<VPath> mVGList = new ArrayList<VPath>(); 560abb7d134c02ac60091108c491dafb00877093170John Hoford 561abb7d134c02ac60091108c491dafb00877093170John Hoford public void add(VPath path) { 562abb7d134c02ac60091108c491dafb00877093170John Hoford String id = path.getID(); 563abb7d134c02ac60091108c491dafb00877093170John Hoford mVGPathMap.put(id, path); 564abb7d134c02ac60091108c491dafb00877093170John Hoford mVGList.add(path); 565abb7d134c02ac60091108c491dafb00877093170John Hoford } 566abb7d134c02ac60091108c491dafb00877093170John Hoford 567abb7d134c02ac60091108c491dafb00877093170John Hoford /** 568abb7d134c02ac60091108c491dafb00877093170John Hoford * Must return in order of adding 569abb7d134c02ac60091108c491dafb00877093170John Hoford * @return ordered list of paths 570abb7d134c02ac60091108c491dafb00877093170John Hoford */ 571abb7d134c02ac60091108c491dafb00877093170John Hoford public Collection<VPath> getPaths() { 572abb7d134c02ac60091108c491dafb00877093170John Hoford return mVGList; 573abb7d134c02ac60091108c491dafb00877093170John Hoford } 574abb7d134c02ac60091108c491dafb00877093170John Hoford 575abb7d134c02ac60091108c491dafb00877093170John Hoford } 576abb7d134c02ac60091108c491dafb00877093170John Hoford 577abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VPath { 578abb7d134c02ac60091108c491dafb00877093170John Hoford private static final int MAX_STATES = 10; 5799453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 5809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private int[] mThemeAttrs; 5819453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 582abb7d134c02ac60091108c491dafb00877093170John Hoford int mStrokeColor = 0; 583abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeWidth = 0; 584abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeOpacity = Float.NaN; 5859453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 586abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillColor = 0; 587abb7d134c02ac60091108c491dafb00877093170John Hoford int mFillRule; 588abb7d134c02ac60091108c491dafb00877093170John Hoford float mFillOpacity = Float.NaN; 5899453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 590abb7d134c02ac60091108c491dafb00877093170John Hoford float mRotate = 0; 591abb7d134c02ac60091108c491dafb00877093170John Hoford float mPivotX = 0; 592abb7d134c02ac60091108c491dafb00877093170John Hoford float mPivotY = 0; 5939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 594abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathStart = 0; 595abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathEnd = 1; 596abb7d134c02ac60091108c491dafb00877093170John Hoford float mTrimPathOffset = 0; 5979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 598abb7d134c02ac60091108c491dafb00877093170John Hoford boolean mClip = false; 5994b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; 6004b3988d159e1c9faa2a7e16c9aca9951264bb429Alan Viverette Paint.Join mStrokeLineJoin = Paint.Join.MITER; 601abb7d134c02ac60091108c491dafb00877093170John Hoford float mStrokeMiterlimit = 4; 6029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private VNode[] mNode = null; 6049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private String mId; 605abb7d134c02ac60091108c491dafb00877093170John Hoford private int[] mCheckState = new int[MAX_STATES]; 606abb7d134c02ac60091108c491dafb00877093170John Hoford private boolean[] mCheckValue = new boolean[MAX_STATES]; 607abb7d134c02ac60091108c491dafb00877093170John Hoford private int mNumberOfStates = 0; 608abb7d134c02ac60091108c491dafb00877093170John Hoford 6099453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public VPath() { 6109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette // Empty constructor. 6119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6139453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public VPath(VPath p) { 6149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette copyFrom(p); 6159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 617abb7d134c02ac60091108c491dafb00877093170John Hoford public void toPath(Path path) { 618abb7d134c02ac60091108c491dafb00877093170John Hoford path.reset(); 619abb7d134c02ac60091108c491dafb00877093170John Hoford if (mNode != null) { 620abb7d134c02ac60091108c491dafb00877093170John Hoford VNode.createPath(mNode, path); 621abb7d134c02ac60091108c491dafb00877093170John Hoford } 622abb7d134c02ac60091108c491dafb00877093170John Hoford } 623abb7d134c02ac60091108c491dafb00877093170John Hoford 6247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette public String getID() { 625abb7d134c02ac60091108c491dafb00877093170John Hoford return mId; 626abb7d134c02ac60091108c491dafb00877093170John Hoford } 627abb7d134c02ac60091108c491dafb00877093170John Hoford 6287f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { 6297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 6307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_BUTT: 6317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.BUTT; 6327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_ROUND: 6337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.ROUND; 6347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINECAP_SQUARE: 6357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Cap.SQUARE; 6367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 6377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 6387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6417f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) { 6427f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette switch (id) { 6437f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_MITER: 6447f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.MITER; 6457f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_ROUND: 6467f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.ROUND; 6477f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette case LINEJOIN_BEVEL: 6487f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return Paint.Join.BEVEL; 6497f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette default: 6507f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette return defValue; 6517f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6527f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6537f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void inflate(Resources r, AttributeSet attrs, Theme theme) { 6559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath); 6569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final int[] themeAttrs = a.extractThemeAttrs(); 6579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mThemeAttrs = themeAttrs; 6589453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6597f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // NOTE: The set of attributes loaded here MUST match the 6607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette // set of attributes loaded in applyTheme. 6617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_clipToPath] == 0) { 6627f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 6637f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) { 6667f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mId = a.getString(R.styleable.VectorDrawablePath_name); 6677f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) { 6707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 6717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 672abb7d134c02ac60091108c491dafb00877093170John Hoford 6739453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) { 6747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 6759453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 6769453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fillOpacity] == 0) { 6787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 679abb7d134c02ac60091108c491dafb00877093170John Hoford } 6809453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) { 6827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate); 6837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6849453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) { 6867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX); 687abb7d134c02ac60091108c491dafb00877093170John Hoford } 6889453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 6897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) { 6907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY); 6917f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6927f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6937f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 6947f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) { 6957f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap( 6967f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 6977f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 6987f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 6997f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7007f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeLineJoin] == 0) { 7017f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin( 7027f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette a.getInt(R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 703abb7d134c02ac60091108c491dafb00877093170John Hoford } 7049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7057f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7067f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeMiterLimit] == 0) { 7077f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 7087f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 7097f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7109453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7119453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_stroke] == 0) { 7129453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 713abb7d134c02ac60091108c491dafb00877093170John Hoford } 7149453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7159453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (themeAttrs == null 7169453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_strokeOpacity] == 0) { 7179453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeOpacity = a.getFloat( 7187f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 7199453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7209453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7217f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeWidth] == 0) { 7227f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 7237f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7247f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7257f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_trimPathEnd] == 0) { 7267f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 7277f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7289453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7297f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7307f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathOffset] == 0) { 7317f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 7327f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 7337f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7347f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7357f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (themeAttrs == null 7367f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette || themeAttrs[R.styleable.VectorDrawablePath_trimPathStart] == 0) { 7377f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 7387f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 7397f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette } 7407f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7419453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 7429453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 743abb7d134c02ac60091108c491dafb00877093170John Hoford a.recycle(); 744abb7d134c02ac60091108c491dafb00877093170John Hoford } 745abb7d134c02ac60091108c491dafb00877093170John Hoford 7469453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public boolean canApplyTheme() { 7479453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return mThemeAttrs != null; 7489453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7499453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7509453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette public void applyTheme(Theme t) { 7519453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (mThemeAttrs == null) { 7529453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette return; 7539453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7549453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7559453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette final TypedArray a = t.resolveAttributes( 7569453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0); 7579453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7587f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip); 7599453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7607f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_name)) { 7617f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mId = a.getString(R.styleable.VectorDrawablePath_name); 7629453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7639453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7647f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) { 7657f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData)); 7669453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7679453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7687f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); 7697f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); 7707f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7717f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate); 7727f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX); 7737f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY); 7747f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7757f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = getStrokeLineCap(a.getInt( 7767f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); 7777f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = getStrokeLineJoin(a.getInt( 7787f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); 7797f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeMiterlimit = a.getFloat( 7807f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); 7817f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_stroke, mStrokeColor); 7827f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeOpacity = a.getFloat( 7837f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_strokeOpacity, mStrokeOpacity); 7847f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth); 7857f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette 7867f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd); 7877f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathOffset = a.getFloat( 7887f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); 7897f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mTrimPathStart = a.getFloat( 7907f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); 7919453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7929453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette updateColorAlphas(); 7939453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 7949453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 7959453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette private void updateColorAlphas() { 7969453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mFillOpacity)) { 7979453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mFillColor &= 0x00FFFFFF; 7989453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mFillColor |= ((int) (0xFF * mFillOpacity)) << 24; 7999453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8009453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 8019453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette if (!Float.isNaN(mStrokeOpacity)) { 8029453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor &= 0x00FFFFFF; 8039453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24; 8049453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8059453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette } 8069453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 807abb7d134c02ac60091108c491dafb00877093170John Hoford private static int nextStart(String s, int end) { 808abb7d134c02ac60091108c491dafb00877093170John Hoford char c; 809abb7d134c02ac60091108c491dafb00877093170John Hoford 810abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < s.length()) { 811abb7d134c02ac60091108c491dafb00877093170John Hoford c = s.charAt(end); 812abb7d134c02ac60091108c491dafb00877093170John Hoford if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { 813abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 814abb7d134c02ac60091108c491dafb00877093170John Hoford } 815abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 816abb7d134c02ac60091108c491dafb00877093170John Hoford } 817abb7d134c02ac60091108c491dafb00877093170John Hoford return end; 818abb7d134c02ac60091108c491dafb00877093170John Hoford } 819abb7d134c02ac60091108c491dafb00877093170John Hoford 820abb7d134c02ac60091108c491dafb00877093170John Hoford private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) { 821abb7d134c02ac60091108c491dafb00877093170John Hoford list.add(new VectorDrawable.VNode(cmd, val)); 822abb7d134c02ac60091108c491dafb00877093170John Hoford } 823abb7d134c02ac60091108c491dafb00877093170John Hoford 824abb7d134c02ac60091108c491dafb00877093170John Hoford /** 825abb7d134c02ac60091108c491dafb00877093170John Hoford * parse the floats in the string 826abb7d134c02ac60091108c491dafb00877093170John Hoford * this is an optimized version of 827abb7d134c02ac60091108c491dafb00877093170John Hoford * parseFloat(s.split(",|\\s")); 828abb7d134c02ac60091108c491dafb00877093170John Hoford * 829abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string containing a command and list of floats 830abb7d134c02ac60091108c491dafb00877093170John Hoford * @return array of floats 831abb7d134c02ac60091108c491dafb00877093170John Hoford */ 832abb7d134c02ac60091108c491dafb00877093170John Hoford private static float[] getFloats(String s) { 833abb7d134c02ac60091108c491dafb00877093170John Hoford if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { 834abb7d134c02ac60091108c491dafb00877093170John Hoford return new float[0]; 835abb7d134c02ac60091108c491dafb00877093170John Hoford } 836abb7d134c02ac60091108c491dafb00877093170John Hoford try { 837abb7d134c02ac60091108c491dafb00877093170John Hoford float[] tmp = new float[s.length()]; 838abb7d134c02ac60091108c491dafb00877093170John Hoford int count = 0; 839abb7d134c02ac60091108c491dafb00877093170John Hoford int pos = 1, end; 840abb7d134c02ac60091108c491dafb00877093170John Hoford while ((end = extract(s, pos)) >= 0) { 841abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < end) { 842abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, end)); 843abb7d134c02ac60091108c491dafb00877093170John Hoford } 844abb7d134c02ac60091108c491dafb00877093170John Hoford pos = end + 1; 845abb7d134c02ac60091108c491dafb00877093170John Hoford } 846abb7d134c02ac60091108c491dafb00877093170John Hoford // handle the final float if there is one 847abb7d134c02ac60091108c491dafb00877093170John Hoford if (pos < s.length()) { 848abb7d134c02ac60091108c491dafb00877093170John Hoford tmp[count++] = Float.parseFloat(s.substring(pos, s.length())); 849abb7d134c02ac60091108c491dafb00877093170John Hoford } 850abb7d134c02ac60091108c491dafb00877093170John Hoford return Arrays.copyOf(tmp, count); 851abb7d134c02ac60091108c491dafb00877093170John Hoford } catch (NumberFormatException e){ 852abb7d134c02ac60091108c491dafb00877093170John Hoford Log.e(LOGTAG,"error in parsing \""+s+"\""); 853abb7d134c02ac60091108c491dafb00877093170John Hoford throw e; 854abb7d134c02ac60091108c491dafb00877093170John Hoford } 855abb7d134c02ac60091108c491dafb00877093170John Hoford } 856abb7d134c02ac60091108c491dafb00877093170John Hoford 857abb7d134c02ac60091108c491dafb00877093170John Hoford /** 858abb7d134c02ac60091108c491dafb00877093170John Hoford * calculate the position of the next comma or space 859abb7d134c02ac60091108c491dafb00877093170John Hoford * @param s the string to search 860abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start the position to start searching 861abb7d134c02ac60091108c491dafb00877093170John Hoford * @return the position of the next comma or space or -1 if none found 862abb7d134c02ac60091108c491dafb00877093170John Hoford */ 863abb7d134c02ac60091108c491dafb00877093170John Hoford private static int extract(String s, int start) { 864abb7d134c02ac60091108c491dafb00877093170John Hoford int space = s.indexOf(' ', start); 865abb7d134c02ac60091108c491dafb00877093170John Hoford int comma = s.indexOf(',', start); 866abb7d134c02ac60091108c491dafb00877093170John Hoford if (space == -1) { 867abb7d134c02ac60091108c491dafb00877093170John Hoford return comma; 868abb7d134c02ac60091108c491dafb00877093170John Hoford } 869abb7d134c02ac60091108c491dafb00877093170John Hoford if (comma == -1) { 870abb7d134c02ac60091108c491dafb00877093170John Hoford return space; 871abb7d134c02ac60091108c491dafb00877093170John Hoford } 872abb7d134c02ac60091108c491dafb00877093170John Hoford return (comma > space) ? space : comma; 873abb7d134c02ac60091108c491dafb00877093170John Hoford } 874abb7d134c02ac60091108c491dafb00877093170John Hoford 875abb7d134c02ac60091108c491dafb00877093170John Hoford private VectorDrawable.VNode[] parsePath(String value) { 876abb7d134c02ac60091108c491dafb00877093170John Hoford int start = 0; 877abb7d134c02ac60091108c491dafb00877093170John Hoford int end = 1; 878abb7d134c02ac60091108c491dafb00877093170John Hoford 879abb7d134c02ac60091108c491dafb00877093170John Hoford ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>(); 880abb7d134c02ac60091108c491dafb00877093170John Hoford while (end < value.length()) { 881abb7d134c02ac60091108c491dafb00877093170John Hoford end = nextStart(value, end); 882abb7d134c02ac60091108c491dafb00877093170John Hoford String s = value.substring(start, end); 883abb7d134c02ac60091108c491dafb00877093170John Hoford float[] val = getFloats(s); 884abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, s.charAt(0), val); 885abb7d134c02ac60091108c491dafb00877093170John Hoford 886abb7d134c02ac60091108c491dafb00877093170John Hoford start = end; 887abb7d134c02ac60091108c491dafb00877093170John Hoford end++; 888abb7d134c02ac60091108c491dafb00877093170John Hoford } 889abb7d134c02ac60091108c491dafb00877093170John Hoford if ((end - start) == 1 && start < value.length()) { 890abb7d134c02ac60091108c491dafb00877093170John Hoford 891abb7d134c02ac60091108c491dafb00877093170John Hoford addNode(list, value.charAt(start), new float[0]); 892abb7d134c02ac60091108c491dafb00877093170John Hoford } 893abb7d134c02ac60091108c491dafb00877093170John Hoford return list.toArray(new VectorDrawable.VNode[list.size()]); 894abb7d134c02ac60091108c491dafb00877093170John Hoford } 895abb7d134c02ac60091108c491dafb00877093170John Hoford 896abb7d134c02ac60091108c491dafb00877093170John Hoford public void copyFrom(VPath p1) { 897abb7d134c02ac60091108c491dafb00877093170John Hoford mNode = new VNode[p1.mNode.length]; 898abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mNode.length; i++) { 899abb7d134c02ac60091108c491dafb00877093170John Hoford mNode[i] = new VNode(p1.mNode[i]); 900abb7d134c02ac60091108c491dafb00877093170John Hoford } 901abb7d134c02ac60091108c491dafb00877093170John Hoford mId = p1.mId; 902abb7d134c02ac60091108c491dafb00877093170John Hoford mStrokeColor = p1.mStrokeColor; 903abb7d134c02ac60091108c491dafb00877093170John Hoford mFillColor = p1.mFillColor; 904abb7d134c02ac60091108c491dafb00877093170John Hoford mStrokeWidth = p1.mStrokeWidth; 905abb7d134c02ac60091108c491dafb00877093170John Hoford mRotate = p1.mRotate; 906abb7d134c02ac60091108c491dafb00877093170John Hoford mPivotX = p1.mPivotX; 907abb7d134c02ac60091108c491dafb00877093170John Hoford mPivotY = p1.mPivotY; 908abb7d134c02ac60091108c491dafb00877093170John Hoford mTrimPathStart = p1.mTrimPathStart; 909abb7d134c02ac60091108c491dafb00877093170John Hoford mTrimPathEnd = p1.mTrimPathEnd; 910abb7d134c02ac60091108c491dafb00877093170John Hoford mTrimPathOffset = p1.mTrimPathOffset; 9117f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineCap = p1.mStrokeLineCap; 9127f1ab7a43fd7e65bbd7460334014ecc73dbb1b8dAlan Viverette mStrokeLineJoin = p1.mStrokeLineJoin; 913abb7d134c02ac60091108c491dafb00877093170John Hoford mStrokeMiterlimit = p1.mStrokeMiterlimit; 914abb7d134c02ac60091108c491dafb00877093170John Hoford mNumberOfStates = p1.mNumberOfStates; 915abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < mNumberOfStates; i++) { 916abb7d134c02ac60091108c491dafb00877093170John Hoford mCheckState[i] = p1.mCheckState[i]; 917abb7d134c02ac60091108c491dafb00877093170John Hoford mCheckValue[i] = p1.mCheckValue[i]; 918abb7d134c02ac60091108c491dafb00877093170John Hoford } 919abb7d134c02ac60091108c491dafb00877093170John Hoford 920abb7d134c02ac60091108c491dafb00877093170John Hoford mFillRule = p1.mFillRule; 921abb7d134c02ac60091108c491dafb00877093170John Hoford } 922abb7d134c02ac60091108c491dafb00877093170John Hoford } 923abb7d134c02ac60091108c491dafb00877093170John Hoford 924abb7d134c02ac60091108c491dafb00877093170John Hoford private static class VNode { 9255c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private char mType; 9265c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette private float[] mParams; 9279453b7cfd4bbb35467bd7f947f850bd154982fceAlan Viverette 928abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(char type, float[] params) { 9295c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = type; 9305c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = params; 931abb7d134c02ac60091108c491dafb00877093170John Hoford } 932abb7d134c02ac60091108c491dafb00877093170John Hoford 933abb7d134c02ac60091108c491dafb00877093170John Hoford public VNode(VNode n) { 9345c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mType = n.mType; 9355c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette mParams = Arrays.copyOf(n.mParams, n.mParams.length); 936abb7d134c02ac60091108c491dafb00877093170John Hoford } 937abb7d134c02ac60091108c491dafb00877093170John Hoford 938abb7d134c02ac60091108c491dafb00877093170John Hoford public static void createPath(VNode[] node, Path path) { 9395c981a100ef30d2925588b69f8b9fe349ee5bfdeAlan Viverette float[] current = new float[4]; 94033ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCommand = 'm'; 941abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < node.length; i++) { 94233ed52eff4b41f88858874e1af7723277a041b56ztenghui addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); 94333ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCommand = node[i].mType; 944abb7d134c02ac60091108c491dafb00877093170John Hoford } 945abb7d134c02ac60091108c491dafb00877093170John Hoford } 946abb7d134c02ac60091108c491dafb00877093170John Hoford 94733ed52eff4b41f88858874e1af7723277a041b56ztenghui private static void addCommand(Path path, float[] current, 94833ed52eff4b41f88858874e1af7723277a041b56ztenghui char previousCmd, char cmd, float[] val) { 949abb7d134c02ac60091108c491dafb00877093170John Hoford 950abb7d134c02ac60091108c491dafb00877093170John Hoford int incr = 2; 951abb7d134c02ac60091108c491dafb00877093170John Hoford float currentX = current[0]; 952abb7d134c02ac60091108c491dafb00877093170John Hoford float currentY = current[1]; 953abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointX = current[2]; 954abb7d134c02ac60091108c491dafb00877093170John Hoford float ctrlPointY = current[3]; 95533ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointX; 95633ed52eff4b41f88858874e1af7723277a041b56ztenghui float reflectiveCtrlPointY; 957abb7d134c02ac60091108c491dafb00877093170John Hoford 958abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 959abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': 960abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': 961abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 962abb7d134c02ac60091108c491dafb00877093170John Hoford return; 963abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': 964abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': 965abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': 966abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': 967abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': 968abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': 969abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 2; 970abb7d134c02ac60091108c491dafb00877093170John Hoford break; 971abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': 972abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': 973abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': 974abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': 975abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 1; 976abb7d134c02ac60091108c491dafb00877093170John Hoford break; 977abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': 978abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': 979abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 6; 980abb7d134c02ac60091108c491dafb00877093170John Hoford break; 981abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': 982abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': 983abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': 984abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': 985abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 4; 986abb7d134c02ac60091108c491dafb00877093170John Hoford break; 987abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': 988abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': 989abb7d134c02ac60091108c491dafb00877093170John Hoford incr = 7; 990abb7d134c02ac60091108c491dafb00877093170John Hoford break; 991abb7d134c02ac60091108c491dafb00877093170John Hoford } 992abb7d134c02ac60091108c491dafb00877093170John Hoford for (int k = 0; k < val.length; k += incr) { 993abb7d134c02ac60091108c491dafb00877093170John Hoford switch (cmd) { 994abb7d134c02ac60091108c491dafb00877093170John Hoford case 'm': // moveto - Start a new sub-path (relative) 995abb7d134c02ac60091108c491dafb00877093170John Hoford path.rMoveTo(val[k + 0], val[k + 1]); 996abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 997abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 998abb7d134c02ac60091108c491dafb00877093170John Hoford break; 999abb7d134c02ac60091108c491dafb00877093170John Hoford case 'M': // moveto - Start a new sub-path 1000abb7d134c02ac60091108c491dafb00877093170John Hoford path.moveTo(val[k + 0], val[k + 1]); 1001abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1002abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1003abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1004abb7d134c02ac60091108c491dafb00877093170John Hoford case 'l': // lineto - Draw a line from the current point (relative) 1005abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], val[k + 1]); 1006abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1007abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1008abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1009abb7d134c02ac60091108c491dafb00877093170John Hoford case 'L': // lineto - Draw a line from the current point 1010abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], val[k + 1]); 1011abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1012abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 1]; 1013abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1014abb7d134c02ac60091108c491dafb00877093170John Hoford case 'z': // closepath - Close the current subpath 1015abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Z': // closepath - Close the current subpath 1016abb7d134c02ac60091108c491dafb00877093170John Hoford path.close(); 1017abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1018abb7d134c02ac60091108c491dafb00877093170John Hoford case 'h': // horizontal lineto - Draws a horizontal line (relative) 1019abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(val[k + 0], 0); 1020abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1021abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1022abb7d134c02ac60091108c491dafb00877093170John Hoford case 'H': // horizontal lineto - Draws a horizontal line 1023abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(val[k + 0], currentY); 1024abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 1025abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1026abb7d134c02ac60091108c491dafb00877093170John Hoford case 'v': // vertical lineto - Draws a vertical line from the current point (r) 1027abb7d134c02ac60091108c491dafb00877093170John Hoford path.rLineTo(0, val[k + 0]); 1028abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 0]; 1029abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1030abb7d134c02ac60091108c491dafb00877093170John Hoford case 'V': // vertical lineto - Draws a vertical line from the current point 1031abb7d134c02ac60091108c491dafb00877093170John Hoford path.lineTo(currentX, val[k + 0]); 1032abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 0]; 1033abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1034abb7d134c02ac60091108c491dafb00877093170John Hoford case 'c': // curveto - Draws a cubic Bézier curve (relative) 103533ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 103633ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1037abb7d134c02ac60091108c491dafb00877093170John Hoford 1038abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 2]; 1039abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 3]; 1040abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 4]; 1041abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 5]; 1042abb7d134c02ac60091108c491dafb00877093170John Hoford 1043abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1044abb7d134c02ac60091108c491dafb00877093170John Hoford case 'C': // curveto - Draws a cubic Bézier curve 104533ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], 104633ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 4], val[k + 5]); 1047abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 4]; 1048abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 5]; 1049abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 2]; 1050abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 3]; 1051abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1052abb7d134c02ac60091108c491dafb00877093170John Hoford case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) 105333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 105433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 105533ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 105633ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 105733ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 105833ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 105933ed52eff4b41f88858874e1af7723277a041b56ztenghui } 106033ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1061abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1], 1062abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], val[k + 3]); 1063abb7d134c02ac60091108c491dafb00877093170John Hoford 1064abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX + val[k + 0]; 1065abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY + val[k + 1]; 1066abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1067abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1068abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1069abb7d134c02ac60091108c491dafb00877093170John Hoford case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) 107033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 107133ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 107233ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'c' || previousCmd == 's' 107333ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'C' || previousCmd == 'S') { 107433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 107533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 107633ed52eff4b41f88858874e1af7723277a041b56ztenghui } 107733ed52eff4b41f88858874e1af7723277a041b56ztenghui path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 107833ed52eff4b41f88858874e1af7723277a041b56ztenghui val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1079abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1080abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 108133ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 108233ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1083abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1084abb7d134c02ac60091108c491dafb00877093170John Hoford case 'q': // Draws a quadratic Bézier (relative) 1085abb7d134c02ac60091108c491dafb00877093170John Hoford path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 108633ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = currentX + val[k + 0]; 108733ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = currentY + val[k + 1]; 1088abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 2]; 1089abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 3]; 1090abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1091abb7d134c02ac60091108c491dafb00877093170John Hoford case 'Q': // Draws a quadratic Bézier 1092abb7d134c02ac60091108c491dafb00877093170John Hoford path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); 1093abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = val[k + 0]; 1094abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = val[k + 1]; 109533ed52eff4b41f88858874e1af7723277a041b56ztenghui currentX = val[k + 2]; 109633ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 3]; 1097abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1098abb7d134c02ac60091108c491dafb00877093170John Hoford case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) 109933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 0; 110033ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 0; 110133ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 110233ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 110333ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX - ctrlPointX; 110433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY - ctrlPointY; 110533ed52eff4b41f88858874e1af7723277a041b56ztenghui } 110633ed52eff4b41f88858874e1af7723277a041b56ztenghui path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1107abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 1108175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointX = currentX + reflectiveCtrlPointX; 1109175f3c892c2c0bd64e32484a2b430e7c59907243ztenghui ctrlPointY = currentY + reflectiveCtrlPointY; 1110abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 0]; 1111abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 1]; 1112abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1113abb7d134c02ac60091108c491dafb00877093170John Hoford case 'T': // Draws a quadratic Bézier curve (reflective control point) 111433ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = currentX; 111533ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = currentY; 111633ed52eff4b41f88858874e1af7723277a041b56ztenghui if (previousCmd == 'q' || previousCmd == 't' 111733ed52eff4b41f88858874e1af7723277a041b56ztenghui || previousCmd == 'Q' || previousCmd == 'T') { 111833ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 111933ed52eff4b41f88858874e1af7723277a041b56ztenghui reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 112033ed52eff4b41f88858874e1af7723277a041b56ztenghui } 112133ed52eff4b41f88858874e1af7723277a041b56ztenghui path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 1122abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], val[k + 1]); 112333ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointX = reflectiveCtrlPointX; 112433ed52eff4b41f88858874e1af7723277a041b56ztenghui ctrlPointY = reflectiveCtrlPointY; 1125abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 0]; 112633ed52eff4b41f88858874e1af7723277a041b56ztenghui currentY = val[k + 1]; 1127abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1128abb7d134c02ac60091108c491dafb00877093170John Hoford case 'a': // Draws an elliptical arc 1129abb7d134c02ac60091108c491dafb00877093170John Hoford // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 1130abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1131abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1132abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1133abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5] + currentX, 1134abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6] + currentY, 1135abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1136abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1137abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1138abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1139abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1140abb7d134c02ac60091108c491dafb00877093170John Hoford currentX += val[k + 5]; 1141abb7d134c02ac60091108c491dafb00877093170John Hoford currentY += val[k + 6]; 1142abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1143abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1144abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1145abb7d134c02ac60091108c491dafb00877093170John Hoford case 'A': // Draws an elliptical arc 1146abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(path, 1147abb7d134c02ac60091108c491dafb00877093170John Hoford currentX, 1148abb7d134c02ac60091108c491dafb00877093170John Hoford currentY, 1149abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 5], 1150abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 6], 1151abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 0], 1152abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 1], 1153abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 2], 1154abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 3] != 0, 1155abb7d134c02ac60091108c491dafb00877093170John Hoford val[k + 4] != 0); 1156abb7d134c02ac60091108c491dafb00877093170John Hoford currentX = val[k + 5]; 1157abb7d134c02ac60091108c491dafb00877093170John Hoford currentY = val[k + 6]; 1158abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointX = currentX; 1159abb7d134c02ac60091108c491dafb00877093170John Hoford ctrlPointY = currentY; 1160abb7d134c02ac60091108c491dafb00877093170John Hoford break; 1161abb7d134c02ac60091108c491dafb00877093170John Hoford } 116233ed52eff4b41f88858874e1af7723277a041b56ztenghui previousCmd = cmd; 1163abb7d134c02ac60091108c491dafb00877093170John Hoford } 1164abb7d134c02ac60091108c491dafb00877093170John Hoford current[0] = currentX; 1165abb7d134c02ac60091108c491dafb00877093170John Hoford current[1] = currentY; 1166abb7d134c02ac60091108c491dafb00877093170John Hoford current[2] = ctrlPointX; 1167abb7d134c02ac60091108c491dafb00877093170John Hoford current[3] = ctrlPointY; 1168abb7d134c02ac60091108c491dafb00877093170John Hoford } 1169abb7d134c02ac60091108c491dafb00877093170John Hoford 1170abb7d134c02ac60091108c491dafb00877093170John Hoford private static void drawArc(Path p, 1171abb7d134c02ac60091108c491dafb00877093170John Hoford float x0, 1172abb7d134c02ac60091108c491dafb00877093170John Hoford float y0, 1173abb7d134c02ac60091108c491dafb00877093170John Hoford float x1, 1174abb7d134c02ac60091108c491dafb00877093170John Hoford float y1, 1175abb7d134c02ac60091108c491dafb00877093170John Hoford float a, 1176abb7d134c02ac60091108c491dafb00877093170John Hoford float b, 1177abb7d134c02ac60091108c491dafb00877093170John Hoford float theta, 1178abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isMoreThanHalf, 1179abb7d134c02ac60091108c491dafb00877093170John Hoford boolean isPositiveArc) { 1180abb7d134c02ac60091108c491dafb00877093170John Hoford 1181abb7d134c02ac60091108c491dafb00877093170John Hoford /* Convert rotation angle from degrees to radians */ 1182abb7d134c02ac60091108c491dafb00877093170John Hoford double thetaD = Math.toRadians(theta); 1183abb7d134c02ac60091108c491dafb00877093170John Hoford /* Pre-compute rotation matrix entries */ 1184abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(thetaD); 1185abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(thetaD); 1186abb7d134c02ac60091108c491dafb00877093170John Hoford /* Transform (x0, y0) and (x1, y1) into unit space */ 1187abb7d134c02ac60091108c491dafb00877093170John Hoford /* using (inverse) rotation, followed by (inverse) scale */ 1188abb7d134c02ac60091108c491dafb00877093170John Hoford double x0p = (x0 * cosTheta + y0 * sinTheta) / a; 1189abb7d134c02ac60091108c491dafb00877093170John Hoford double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; 1190abb7d134c02ac60091108c491dafb00877093170John Hoford double x1p = (x1 * cosTheta + y1 * sinTheta) / a; 1191abb7d134c02ac60091108c491dafb00877093170John Hoford double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; 1192abb7d134c02ac60091108c491dafb00877093170John Hoford 1193abb7d134c02ac60091108c491dafb00877093170John Hoford /* Compute differences and averages */ 1194abb7d134c02ac60091108c491dafb00877093170John Hoford double dx = x0p - x1p; 1195abb7d134c02ac60091108c491dafb00877093170John Hoford double dy = y0p - y1p; 1196abb7d134c02ac60091108c491dafb00877093170John Hoford double xm = (x0p + x1p) / 2; 1197abb7d134c02ac60091108c491dafb00877093170John Hoford double ym = (y0p + y1p) / 2; 1198abb7d134c02ac60091108c491dafb00877093170John Hoford /* Solve for intersecting unit circles */ 1199abb7d134c02ac60091108c491dafb00877093170John Hoford double dsq = dx * dx + dy * dy; 1200abb7d134c02ac60091108c491dafb00877093170John Hoford if (dsq == 0.0) { 1201abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, " Points are coincident"); 1202abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are coincident */ 1203abb7d134c02ac60091108c491dafb00877093170John Hoford } 1204abb7d134c02ac60091108c491dafb00877093170John Hoford double disc = 1.0 / dsq - 1.0 / 4.0; 1205abb7d134c02ac60091108c491dafb00877093170John Hoford if (disc < 0.0) { 1206abb7d134c02ac60091108c491dafb00877093170John Hoford Log.w(LOGTAG, "Points are too far apart " + dsq); 1207abb7d134c02ac60091108c491dafb00877093170John Hoford float adjust = (float) (Math.sqrt(dsq) / 1.99999); 1208abb7d134c02ac60091108c491dafb00877093170John Hoford drawArc(p, x0, y0, x1, y1, a * adjust, 1209abb7d134c02ac60091108c491dafb00877093170John Hoford b * adjust, theta, isMoreThanHalf, isPositiveArc); 1210abb7d134c02ac60091108c491dafb00877093170John Hoford return; /* Points are too far apart */ 1211abb7d134c02ac60091108c491dafb00877093170John Hoford } 1212abb7d134c02ac60091108c491dafb00877093170John Hoford double s = Math.sqrt(disc); 1213abb7d134c02ac60091108c491dafb00877093170John Hoford double sdx = s * dx; 1214abb7d134c02ac60091108c491dafb00877093170John Hoford double sdy = s * dy; 1215abb7d134c02ac60091108c491dafb00877093170John Hoford double cx; 1216abb7d134c02ac60091108c491dafb00877093170John Hoford double cy; 1217abb7d134c02ac60091108c491dafb00877093170John Hoford if (isMoreThanHalf == isPositiveArc) { 1218abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm - sdy; 1219abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym + sdx; 1220abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1221abb7d134c02ac60091108c491dafb00877093170John Hoford cx = xm + sdy; 1222abb7d134c02ac60091108c491dafb00877093170John Hoford cy = ym - sdx; 1223abb7d134c02ac60091108c491dafb00877093170John Hoford } 1224abb7d134c02ac60091108c491dafb00877093170John Hoford 1225abb7d134c02ac60091108c491dafb00877093170John Hoford double eta0 = Math.atan2((y0p - cy), (x0p - cx)); 1226abb7d134c02ac60091108c491dafb00877093170John Hoford 1227abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = Math.atan2((y1p - cy), (x1p - cx)); 1228abb7d134c02ac60091108c491dafb00877093170John Hoford 1229abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep = (eta1 - eta0); 1230abb7d134c02ac60091108c491dafb00877093170John Hoford if (isPositiveArc != (sweep >= 0)) { 1231abb7d134c02ac60091108c491dafb00877093170John Hoford if (sweep > 0) { 1232abb7d134c02ac60091108c491dafb00877093170John Hoford sweep -= 2 * Math.PI; 1233abb7d134c02ac60091108c491dafb00877093170John Hoford } else { 1234abb7d134c02ac60091108c491dafb00877093170John Hoford sweep += 2 * Math.PI; 1235abb7d134c02ac60091108c491dafb00877093170John Hoford } 1236abb7d134c02ac60091108c491dafb00877093170John Hoford } 1237abb7d134c02ac60091108c491dafb00877093170John Hoford 1238abb7d134c02ac60091108c491dafb00877093170John Hoford cx *= a; 1239abb7d134c02ac60091108c491dafb00877093170John Hoford cy *= b; 1240abb7d134c02ac60091108c491dafb00877093170John Hoford double tcx = cx; 1241abb7d134c02ac60091108c491dafb00877093170John Hoford cx = cx * cosTheta - cy * sinTheta; 1242abb7d134c02ac60091108c491dafb00877093170John Hoford cy = tcx * sinTheta + cy * cosTheta; 1243abb7d134c02ac60091108c491dafb00877093170John Hoford 1244abb7d134c02ac60091108c491dafb00877093170John Hoford arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); 1245abb7d134c02ac60091108c491dafb00877093170John Hoford } 1246abb7d134c02ac60091108c491dafb00877093170John Hoford 1247abb7d134c02ac60091108c491dafb00877093170John Hoford /** 1248abb7d134c02ac60091108c491dafb00877093170John Hoford * Converts an arc to cubic Bezier segments and records them in p. 1249abb7d134c02ac60091108c491dafb00877093170John Hoford * 1250abb7d134c02ac60091108c491dafb00877093170John Hoford * @param p The target for the cubic Bezier segments 1251abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cx The x coordinate center of the ellipse 1252abb7d134c02ac60091108c491dafb00877093170John Hoford * @param cy The y coordinate center of the ellipse 1253abb7d134c02ac60091108c491dafb00877093170John Hoford * @param a The radius of the ellipse in the horizontal direction 1254abb7d134c02ac60091108c491dafb00877093170John Hoford * @param b The radius of the ellipse in the vertical direction 1255abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1x E(eta1) x coordinate of the starting point of the arc 1256abb7d134c02ac60091108c491dafb00877093170John Hoford * @param e1y E(eta2) y coordinate of the starting point of the arc 1257abb7d134c02ac60091108c491dafb00877093170John Hoford * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane 1258abb7d134c02ac60091108c491dafb00877093170John Hoford * @param start The start angle of the arc on the ellipse 1259abb7d134c02ac60091108c491dafb00877093170John Hoford * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse 1260abb7d134c02ac60091108c491dafb00877093170John Hoford */ 1261abb7d134c02ac60091108c491dafb00877093170John Hoford private static void arcToBezier(Path p, 1262abb7d134c02ac60091108c491dafb00877093170John Hoford double cx, 1263abb7d134c02ac60091108c491dafb00877093170John Hoford double cy, 1264abb7d134c02ac60091108c491dafb00877093170John Hoford double a, 1265abb7d134c02ac60091108c491dafb00877093170John Hoford double b, 1266abb7d134c02ac60091108c491dafb00877093170John Hoford double e1x, 1267abb7d134c02ac60091108c491dafb00877093170John Hoford double e1y, 1268abb7d134c02ac60091108c491dafb00877093170John Hoford double theta, 1269abb7d134c02ac60091108c491dafb00877093170John Hoford double start, 1270abb7d134c02ac60091108c491dafb00877093170John Hoford double sweep) { 1271abb7d134c02ac60091108c491dafb00877093170John Hoford // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html 1272abb7d134c02ac60091108c491dafb00877093170John Hoford // and http://www.spaceroots.org/documents/ellipse/node22.html 1273abb7d134c02ac60091108c491dafb00877093170John Hoford 1274abb7d134c02ac60091108c491dafb00877093170John Hoford // Maximum of 45 degrees per cubic Bezier segment 1275abb7d134c02ac60091108c491dafb00877093170John Hoford int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); 1276abb7d134c02ac60091108c491dafb00877093170John Hoford 1277abb7d134c02ac60091108c491dafb00877093170John Hoford double eta1 = start; 1278abb7d134c02ac60091108c491dafb00877093170John Hoford double cosTheta = Math.cos(theta); 1279abb7d134c02ac60091108c491dafb00877093170John Hoford double sinTheta = Math.sin(theta); 1280abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta1 = Math.cos(eta1); 1281abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta1 = Math.sin(eta1); 1282abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); 1283abb7d134c02ac60091108c491dafb00877093170John Hoford double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); 1284abb7d134c02ac60091108c491dafb00877093170John Hoford 1285abb7d134c02ac60091108c491dafb00877093170John Hoford double anglePerSegment = sweep / numSegments; 1286abb7d134c02ac60091108c491dafb00877093170John Hoford for (int i = 0; i < numSegments; i++) { 1287abb7d134c02ac60091108c491dafb00877093170John Hoford double eta2 = eta1 + anglePerSegment; 1288abb7d134c02ac60091108c491dafb00877093170John Hoford double sinEta2 = Math.sin(eta2); 1289abb7d134c02ac60091108c491dafb00877093170John Hoford double cosEta2 = Math.cos(eta2); 1290abb7d134c02ac60091108c491dafb00877093170John Hoford double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); 1291abb7d134c02ac60091108c491dafb00877093170John Hoford double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); 1292abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; 1293abb7d134c02ac60091108c491dafb00877093170John Hoford double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; 1294abb7d134c02ac60091108c491dafb00877093170John Hoford double tanDiff2 = Math.tan((eta2 - eta1) / 2); 1295abb7d134c02ac60091108c491dafb00877093170John Hoford double alpha = 1296abb7d134c02ac60091108c491dafb00877093170John Hoford Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; 1297abb7d134c02ac60091108c491dafb00877093170John Hoford double q1x = e1x + alpha * ep1x; 1298abb7d134c02ac60091108c491dafb00877093170John Hoford double q1y = e1y + alpha * ep1y; 1299abb7d134c02ac60091108c491dafb00877093170John Hoford double q2x = e2x - alpha * ep2x; 1300abb7d134c02ac60091108c491dafb00877093170John Hoford double q2y = e2y - alpha * ep2y; 1301abb7d134c02ac60091108c491dafb00877093170John Hoford 1302abb7d134c02ac60091108c491dafb00877093170John Hoford p.cubicTo((float) q1x, 1303abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q1y, 1304abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2x, 1305abb7d134c02ac60091108c491dafb00877093170John Hoford (float) q2y, 1306abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2x, 1307abb7d134c02ac60091108c491dafb00877093170John Hoford (float) e2y); 1308abb7d134c02ac60091108c491dafb00877093170John Hoford eta1 = eta2; 1309abb7d134c02ac60091108c491dafb00877093170John Hoford e1x = e2x; 1310abb7d134c02ac60091108c491dafb00877093170John Hoford e1y = e2y; 1311abb7d134c02ac60091108c491dafb00877093170John Hoford ep1x = ep2x; 1312abb7d134c02ac60091108c491dafb00877093170John Hoford ep1y = ep2y; 1313abb7d134c02ac60091108c491dafb00877093170John Hoford } 1314abb7d134c02ac60091108c491dafb00877093170John Hoford } 1315abb7d134c02ac60091108c491dafb00877093170John Hoford 1316abb7d134c02ac60091108c491dafb00877093170John Hoford } 1317abb7d134c02ac60091108c491dafb00877093170John Hoford} 1318