From 9b2e582052e162194621ff4af673518aaf2124fe Mon Sep 17 00:00:00 2001 From: seven332 Date: Mon, 8 Jun 2015 19:17:12 +0800 Subject: [PATCH] Use VectorOld submodule --- .gitmodules | 3 + app/build.gradle | 1 + .../android/content/res/VectorResources.java | 220 --- .../vectorold/animation/AnimatorInflater.java | 612 ------- .../animation/InterpolatorInflater.java | 125 -- .../vectorold/animation/PathInterpolator.java | 219 --- .../vectorold/content/VectorContext.java | 52 - .../drawable/AnimatedVectorDrawable.java | 430 ----- .../vectorold/drawable/VectorDrawable.java | 1399 ----------------- .../hippo/vectorold/util/DrawableUtils.java | 59 - .../com/hippo/vectorold/util/PathParser.java | 651 -------- app/src/main/res/values/vectorold_attrs.xml | 240 --- settings.gradle | 2 +- vectorold | 1 + 14 files changed, 6 insertions(+), 4008 deletions(-) delete mode 100644 app/src/main/java/android/content/res/VectorResources.java delete mode 100644 app/src/main/java/com/hippo/vectorold/animation/AnimatorInflater.java delete mode 100644 app/src/main/java/com/hippo/vectorold/animation/InterpolatorInflater.java delete mode 100644 app/src/main/java/com/hippo/vectorold/animation/PathInterpolator.java delete mode 100644 app/src/main/java/com/hippo/vectorold/content/VectorContext.java delete mode 100644 app/src/main/java/com/hippo/vectorold/drawable/AnimatedVectorDrawable.java delete mode 100644 app/src/main/java/com/hippo/vectorold/drawable/VectorDrawable.java delete mode 100644 app/src/main/java/com/hippo/vectorold/util/DrawableUtils.java delete mode 100644 app/src/main/java/com/hippo/vectorold/util/PathParser.java delete mode 100644 app/src/main/res/values/vectorold_attrs.xml create mode 160000 vectorold diff --git a/.gitmodules b/.gitmodules index 2e7c00741..beccb9bbb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "unifile"] path = unifile url = https://github.com/seven332/UniFile +[submodule "vectorold"] + path = vectorold + url = https://github.com/seven332/VectorOld diff --git a/app/build.gradle b/app/build.gradle index 3e058a93f..7f7dd733e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,4 +34,5 @@ dependencies { releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':unifile') + compile project(':vectorold') } diff --git a/app/src/main/java/android/content/res/VectorResources.java b/app/src/main/java/android/content/res/VectorResources.java deleted file mode 100644 index 1e678395d..000000000 --- a/app/src/main/java/android/content/res/VectorResources.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2015 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.res; - -import android.content.Context; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.support.v4.util.LongSparseArray; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.util.Xml; - -import com.hippo.vectorold.drawable.AnimatedVectorDrawable; -import com.hippo.vectorold.drawable.VectorDrawable; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.WeakReference; - -// TODO Only load register drawable from itself -/** - * It is a wrap - */ -public class VectorResources extends Resources { - - private static final String TAG = VectorResources.class.getSimpleName(); - - private Context mContext; - private Resources mBase; - - // These are protected by mAccessLock. - - /*package*/ final Object mAccessLock = new Object(); - /*package*/ final LongSparseArray > mDrawableCache - = new LongSparseArray >(0); - /*package*/ final LongSparseArray > mColorDrawableCache - = new LongSparseArray >(0); - - public VectorResources(Context context, Resources res) { - super(res.getAssets(), res.getDisplayMetrics(), res.getConfiguration()); - mContext = context; - mBase = res; - } - - public boolean isBase(Resources res) { - return mBase == res; - } - - @Override - Drawable loadDrawable(TypedValue value, int id) - throws NotFoundException { - boolean isColorDrawable = false; - if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && - value.type <= TypedValue.TYPE_LAST_COLOR_INT) { - isColorDrawable = true; - } - final long key = isColorDrawable ? value.data : - (((long) value.assetCookie) << 32) | value.data; - - Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key); - - if (dr != null) { - return dr; - } - - if (isColorDrawable) { - dr = new ColorDrawable(value.data); - } - - if (dr == null) { - if (value.string == null) { - throw new NotFoundException( - "Resource is not a Drawable (color or path): " + value); - } - - String file = value.string.toString(); - - if (file.endsWith(".xml")) { - // Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); - try { - XmlResourceParser rp = getXml(id); - // XmlResourceParser rp = loadXmlResourceParser( - // file, id, value.assetCookie, "drawable"); - dr = createDrawableFromXml(rp); - rp.close(); - } catch (Exception e) { - // Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - NotFoundException rnf = new NotFoundException( - "File " + file + " from drawable resource ID #0x" - + Integer.toHexString(id)); - rnf.initCause(e); - throw rnf; - } - // Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - - } else { - // Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); - try { - InputStream is = openRawResource(id, value); - //InputStream is = mAssets.openNonAsset( - // value.assetCookie, file, AssetManager.ACCESS_STREAMING); - // System.out.println("Opened file " + file + ": " + is); - dr = Drawable.createFromResourceStream(this, value, is, - file, null); - is.close(); - // System.out.println("Created stream: " + dr); - } catch (Exception e) { - // Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - NotFoundException rnf = new NotFoundException( - "File " + file + " from drawable resource ID #0x" - + Integer.toHexString(id)); - rnf.initCause(e); - throw rnf; - } - // Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - } - } - Drawable.ConstantState cs; - if (dr != null) { - dr.setChangingConfigurations(value.changingConfigurations); - cs = dr.getConstantState(); - if (cs != null) { - synchronized (mAccessLock) { - //Log.i(TAG, "Saving cached drawable @ #" + - // Integer.toHexString(key.intValue()) - // + " in " + this + ": " + cs); - if (isColorDrawable) { - mColorDrawableCache.put(key, new WeakReference(cs)); - } else { - mDrawableCache.put(key, new WeakReference(cs)); - } - } - } - } - - return dr; - } - - private Drawable getCachedDrawable( - LongSparseArray> drawableCache, - long key) { - synchronized (mAccessLock) { - WeakReference wr = drawableCache.get(key); - if (wr != null) { // we have the key - Drawable.ConstantState entry = wr.get(); - if (entry != null) { - //Log.i(TAG, "Returning cached drawable @ #" + - // Integer.toHexString(((Integer)key).intValue()) - // + " in " + this + ": " + entry); - return entry.newDrawable(this); - } - else { // our entry has been purged - drawableCache.delete(key); - } - } - } - return null; - } - - private Drawable createDrawableFromXml(XmlResourceParser parser) - throws XmlPullParserException, IOException { - AttributeSet attrs = Xml.asAttributeSet(parser); - - int type; - while ((type=parser.next()) != XmlPullParser.START_TAG && - type != XmlPullParser.END_DOCUMENT) { - // Empty loop - } - - if (type != XmlPullParser.START_TAG) { - throw new XmlPullParserException("No start tag found"); - } - - Drawable drawable = createDrawableFromXmlInner(parser, attrs); - - if (drawable == null) { - throw new RuntimeException("Unknown initial tag: " + parser.getName()); - } - - return drawable; - } - - private Drawable createDrawableFromXmlInner(XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { - final Drawable drawable; - final String name = parser.getName(); - switch (name) { - case "vector": - VectorDrawable vectorDrawable = new VectorDrawable(); - vectorDrawable.inflate(this, parser, attrs); - drawable = vectorDrawable; - break; - case "animated-vector": - AnimatedVectorDrawable animatedVectorDrawable = new AnimatedVectorDrawable(); - animatedVectorDrawable.inflate(mContext, parser, attrs); - drawable = animatedVectorDrawable; - break; - default: - drawable = Drawable.createFromXmlInner(this, parser, attrs); - } - return drawable; - } -} diff --git a/app/src/main/java/com/hippo/vectorold/animation/AnimatorInflater.java b/app/src/main/java/com/hippo/vectorold/animation/AnimatorInflater.java deleted file mode 100644 index 6105dd0f9..000000000 --- a/app/src/main/java/com/hippo/vectorold/animation/AnimatorInflater.java +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.vectorold.animation; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ArgbEvaluator; -import android.animation.ObjectAnimator; -import android.animation.TypeEvaluator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; -import android.util.Xml; -import android.view.InflateException; - -import com.hippo.ehviewer.R; -import com.hippo.vectorold.util.PathParser; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * This class is used to instantiate animator XML files into Animator objects. - *

- * For performance reasons, inflation relies heavily on pre-processing of - * XML files that is done at build time. Therefore, it is not currently possible - * to use this inflater with an XmlPullParser over a plain XML file at runtime; - * it only works with an XmlPullParser returned from a compiled resource (R. - * something file.) - */ -public class AnimatorInflater { - private static final String TAG = "AnimatorInflater"; - /** - * These flags are used when parsing AnimatorSet objects - */ - private static final int TOGETHER = 0; - private static final int SEQUENTIALLY = 1; - - /** - * Enum values used in XML attributes to indicate the value for mValueType - */ - private static final int VALUE_TYPE_FLOAT = 0; - private static final int VALUE_TYPE_INT = 1; - private static final int VALUE_TYPE_PATH = 2; - private static final int VALUE_TYPE_COLOR = 4; - private static final int VALUE_TYPE_CUSTOM = 5; - - private static final boolean DBG_ANIMATOR_INFLATER = false; - - private static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator(); - - /** - * Loads an {@link android.animation.Animator} object from a resource - * - * @param context Application context used to access resources - * @param id The resource id of the animation to load - * @return The animator object reference by the specified id - * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded - */ - public static Animator loadAnimator(Context context, int id) - throws NotFoundException { - return loadAnimator(context, id, 1); - } - - public static Animator loadAnimator(Context context, int id, float pathErrorScale) { - Resources resources = context.getResources(); - XmlResourceParser parser = null; - try { - parser = resources.getAnimation(id); - return createAnimatorFromXml(context, parser, pathErrorScale); - } catch (XmlPullParserException ex) { - NotFoundException rnf = - new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = - new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } finally { - if (parser != null) parser.close(); - } - } - - /* TODO Not support StateListAnimator - public static StateListAnimator loadStateListAnimator(Context context, int id) - throws NotFoundException { - XmlResourceParser parser = null; - try { - parser = context.getResources().getAnimation(id); - return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); - } catch (XmlPullParserException ex) { - NotFoundException rnf = - new NotFoundException( - "Can't load state list animator resource ID #0x" + - Integer.toHexString(id) - ); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = - new NotFoundException( - "Can't load state list animator resource ID #0x" + - Integer.toHexString(id) - ); - rnf.initCause(ex); - throw rnf; - } finally { - if (parser != null) { - parser.close(); - } - } - } - */ - - /* TODO Not support StateListAnimator - private static StateListAnimator createStateListAnimatorFromXml(Context context, - XmlPullParser parser, AttributeSet attributeSet) - throws IOException, XmlPullParserException { - int type; - StateListAnimator stateListAnimator = new StateListAnimator(); - - while (true) { - type = parser.next(); - switch (type) { - case XmlPullParser.END_DOCUMENT: - case XmlPullParser.END_TAG: - return stateListAnimator; - - case XmlPullParser.START_TAG: - // parse item - Animator animator = null; - if ("item".equals(parser.getName())) { - int attributeCount = parser.getAttributeCount(); - int[] states = new int[attributeCount]; - int stateIndex = 0; - for (int i = 0; i < attributeCount; i++) { - int attrName = attributeSet.getAttributeNameResource(i); - if (attrName == R.attr.animation) { - animator = loadAnimator(context, - attributeSet.getAttributeResourceValue(i, 0)); - } else { - states[stateIndex++] = - attributeSet.getAttributeBooleanValue(i, false) ? - attrName : -attrName; - } - - } - if (animator == null) { - animator = createAnimatorFromXml(context, parser, 1f); - } - - if (animator == null) { - throw new NotFoundException( - "animation state item must have a valid animation"); - } - stateListAnimator - .addState(StateSet.trimStateSet(states, stateIndex), animator); - - } - break; - } - } - } - */ - - /** - * PathDataEvaluator is used to interpolate between two paths which are - * represented in the same format but different control points' values. - * The path is represented as an array of PathDataNode here, which is - * fundamentally an array of floating point numbers. - */ - private static class PathDataEvaluator implements TypeEvaluator { - private PathParser.PathDataNode[] mNodeArray; - - /** - * Create a PathParser.PathDataNode[] that does not reuse the animated value. - * Care must be taken when using this option because on every evaluation - * a new PathParser.PathDataNode[] will be allocated. - */ - private PathDataEvaluator() {} - - /** - * Create a PathDataEvaluator that reuses nodeArray for every evaluate() call. - * Caution must be taken to ensure that the value returned from - * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or - * used across threads. The value will be modified on each evaluate() call. - * - * @param nodeArray The array to modify and return from evaluate. - */ - public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) { - mNodeArray = nodeArray; - } - - @Override - public PathParser.PathDataNode[] evaluate(float fraction, - PathParser.PathDataNode[] startPathData, - PathParser.PathDataNode[] endPathData) { - if (!PathParser.canMorph(startPathData, endPathData)) { - throw new IllegalArgumentException("Can't interpolate between" - + " two incompatible pathData"); - } - - if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) { - mNodeArray = PathParser.deepCopyNodes(startPathData); - } - - for (int i = 0; i < startPathData.length; i++) { - mNodeArray[i].interpolatePathDataNode(startPathData[i], - endPathData[i], fraction); - } - - return mNodeArray; - } - } - - /** - * @param anim The animator, must not be null - * @param arrayAnimator Incoming typed array for Animator's attributes. - * @param arrayObjectAnimator Incoming typed array for Object Animator's - * attributes. - * @param pixelSize The relative pixel size, used to calculate the - * maximum error for path animations. - */ - private static void parseAnimatorFromTypeArray(ValueAnimator anim, - TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) { - long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300); - - long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); - - int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, - VALUE_TYPE_FLOAT); - - TypeEvaluator evaluator = null; - - boolean getFloats = (valueType == VALUE_TYPE_FLOAT); - - TypedValue tvFrom = arrayAnimator.peekValue(R.styleable.Animator_valueFrom); - boolean hasFrom = (tvFrom != null); - int fromType = hasFrom ? tvFrom.type : 0; - TypedValue tvTo = arrayAnimator.peekValue(R.styleable.Animator_valueTo); - boolean hasTo = (tvTo != null); - int toType = hasTo ? tvTo.type : 0; - - // TODO: Further clean up this part of code into 4 types : path, color, - // integer and float. - if (valueType == VALUE_TYPE_PATH) { - evaluator = setupAnimatorForPath(anim, arrayAnimator); - } else { - // Integer and float value types are handled here. - if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && - (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) || - (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) && - (toType <= TypedValue.TYPE_LAST_COLOR_INT))) { - // special case for colors: ignore valueType and get ints - getFloats = false; - evaluator = ARGB_EVALUATOR; - } - setupValues(anim, arrayAnimator, getFloats, hasFrom, fromType, hasTo, toType); - } - - anim.setDuration(duration); - anim.setStartDelay(startDelay); - - if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) { - anim.setRepeatCount( - arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0)); - } - if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) { - anim.setRepeatMode( - arrayAnimator.getInt(R.styleable.Animator_repeatMode, - ValueAnimator.RESTART)); - } - if (evaluator != null) { - anim.setEvaluator(evaluator); - } - - if (arrayObjectAnimator != null) { - setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize); - } - } - - /** - * Setup the Animator to achieve path morphing. - * - * @param anim The target Animator which will be updated. - * @param arrayAnimator TypedArray for the ValueAnimator. - * @return the PathDataEvaluator. - */ - private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim, - TypedArray arrayAnimator) { - TypeEvaluator evaluator = null; - String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom); - String toString = arrayAnimator.getString(R.styleable.Animator_valueTo); - PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString); - PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString); - - if (nodesFrom != null) { - if (nodesTo != null) { - anim.setObjectValues(nodesFrom, nodesTo); - if (!PathParser.canMorph(nodesFrom, nodesTo)) { - throw new InflateException(arrayAnimator.getPositionDescription() - + " Can't morph from " + fromString + " to " + toString); - } - } else { - anim.setObjectValues((Object)nodesFrom); - } - evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom)); - } else if (nodesTo != null) { - anim.setObjectValues((Object)nodesTo); - evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo)); - } - - if (DBG_ANIMATOR_INFLATER && evaluator != null) { - Log.v(TAG, "create a new PathDataEvaluator here"); - } - - return evaluator; - } - - /** - * Setup ObjectAnimator's property or values from pathData. - * - * @param anim The target Animator which will be updated. - * @param arrayObjectAnimator TypedArray for the ObjectAnimator. - * @param getFloats True if the value type is float. - * @param pixelSize The relative pixel size, used to calculate the - * maximum error for path animations. - */ - private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator, - boolean getFloats, float pixelSize) { - ObjectAnimator oa = (ObjectAnimator) anim; - String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); - - // Note that if there is a pathData defined in the Object Animator, - // valueFrom / valueTo will be ignored. - if (pathData != null) { - throw new IllegalStateException("Not support PropertyAnimator_pathData"); - /* TODO Not support pathData - String propertyXName = - arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName); - String propertyYName = - arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName); - - if (propertyXName == null && propertyYName == null) { - throw new InflateException(arrayObjectAnimator.getPositionDescription() - + " propertyXName or propertyYName is needed for PathData"); - } else { - JPath path = JPathParser.createPathFromPathData(pathData); - float error = 0.5f * pixelSize; // max half a pixel error - PathKeyframes keyframeSet = new PathKeyframes(path, error); - Keyframes xKeyframes; - Keyframes yKeyframes; - if (getFloats) { - xKeyframes = keyframeSet.createXFloatKeyframes(); - yKeyframes = keyframeSet.createYFloatKeyframes(); - } else { - xKeyframes = keyframeSet.createXIntKeyframes(); - yKeyframes = keyframeSet.createYIntKeyframes(); - } - PropertyValuesHolder x = null; - PropertyValuesHolder y = null; - if (propertyXName != null) { - x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes); - } - if (propertyYName != null) { - y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes); - } - if (x == null) { - oa.setValues(y); - } else if (y == null) { - oa.setValues(x); - } else { - oa.setValues(x, y); - } - } - */ - } else { - String propertyName = - arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName); - oa.setPropertyName(propertyName); - } - } - - /** - * Setup ValueAnimator's values. - * This will handle all of the integer, float and color types. - * - * @param anim The target Animator which will be updated. - * @param arrayAnimator TypedArray for the ValueAnimator. - * @param getFloats True if the value type is float. - * @param hasFrom True if "valueFrom" exists. - * @param fromType The type of "valueFrom". - * @param hasTo True if "valueTo" exists. - * @param toType The type of "valueTo". - */ - private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator, - boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) { - int valueFromIndex = R.styleable.Animator_valueFrom; - int valueToIndex = R.styleable.Animator_valueTo; - if (getFloats) { - float valueFrom; - float valueTo; - if (hasFrom) { - if (fromType == TypedValue.TYPE_DIMENSION) { - valueFrom = arrayAnimator.getDimension(valueFromIndex, 0f); - } else { - valueFrom = arrayAnimator.getFloat(valueFromIndex, 0f); - } - if (hasTo) { - if (toType == TypedValue.TYPE_DIMENSION) { - valueTo = arrayAnimator.getDimension(valueToIndex, 0f); - } else { - valueTo = arrayAnimator.getFloat(valueToIndex, 0f); - } - anim.setFloatValues(valueFrom, valueTo); - } else { - anim.setFloatValues(valueFrom); - } - } else { - if (toType == TypedValue.TYPE_DIMENSION) { - valueTo = arrayAnimator.getDimension(valueToIndex, 0f); - } else { - valueTo = arrayAnimator.getFloat(valueToIndex, 0f); - } - anim.setFloatValues(valueTo); - } - } else { - int valueFrom; - int valueTo; - if (hasFrom) { - if (fromType == TypedValue.TYPE_DIMENSION) { - valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f); - } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) && - (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) { - valueFrom = arrayAnimator.getColor(valueFromIndex, 0); - } else { - valueFrom = arrayAnimator.getInt(valueFromIndex, 0); - } - if (hasTo) { - if (toType == TypedValue.TYPE_DIMENSION) { - valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); - } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && - (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { - valueTo = arrayAnimator.getColor(valueToIndex, 0); - } else { - valueTo = arrayAnimator.getInt(valueToIndex, 0); - } - anim.setIntValues(valueFrom, valueTo); - } else { - anim.setIntValues(valueFrom); - } - } else { - if (hasTo) { - if (toType == TypedValue.TYPE_DIMENSION) { - valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f); - } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) && - (toType <= TypedValue.TYPE_LAST_COLOR_INT)) { - valueTo = arrayAnimator.getColor(valueToIndex, 0); - } else { - valueTo = arrayAnimator.getInt(valueToIndex, 0); - } - anim.setIntValues(valueTo); - } - } - } - } - - private static Animator createAnimatorFromXml(Context context, XmlPullParser parser, - float pixelSize) - throws XmlPullParserException, IOException { - return createAnimatorFromXml(context, parser, Xml.asAttributeSet(parser), null, 0, - pixelSize); - } - - private static Animator createAnimatorFromXml(Context context, XmlPullParser parser, - AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) - throws XmlPullParserException, IOException { - - Animator anim = null; - ArrayList childAnims = null; - - // Make sure we are on a start tag. - int type; - int depth = parser.getDepth(); - - while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { - - if (type != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - - if (name.equals("objectAnimator")) { - anim = loadObjectAnimator(context, attrs, pixelSize); - } else if (name.equals("animator")) { - anim = loadAnimator(context, attrs, null, pixelSize); - } else if (name.equals("set")) { - anim = new AnimatorSet(); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AnimatorSet); - int ordering = a.getInt(R.styleable.AnimatorSet_ordering, - TOGETHER); - createAnimatorFromXml(context, parser, attrs, (AnimatorSet) anim, ordering, - pixelSize); - a.recycle(); - } else { - throw new RuntimeException("Unknown animator name: " + parser.getName()); - } - - if (parent != null) { - if (childAnims == null) { - childAnims = new ArrayList<>(); - } - childAnims.add(anim); - } - } - if (parent != null && childAnims != null) { - Animator[] animsArray = new Animator[childAnims.size()]; - int index = 0; - for (Animator a : childAnims) { - animsArray[index++] = a; - } - if (sequenceOrdering == TOGETHER) { - parent.playTogether(animsArray); - } else { - parent.playSequentially(animsArray); - } - } - - return anim; - - } - - private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs, - float pathErrorScale) throws NotFoundException { - ObjectAnimator anim = new ObjectAnimator(); - - loadAnimator(context, attrs, anim, pathErrorScale); - - return anim; - } - - /** - * Creates a new animation whose parameters come from the specified context - * and attributes set. - * - * @param context the context - * @param attrs The set of attributes holding the animation parameters - * @param anim Null if this is a ValueAnimator, otherwise this is an - * ObjectAnimator - */ - private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, - ValueAnimator anim, float pathErrorScale) - throws NotFoundException { - - TypedArray arrayAnimator = context.obtainStyledAttributes(attrs, R.styleable.Animator); - TypedArray arrayObjectAnimator = null; - - // If anim is not null, then it is an object animator. - if (anim != null) { - arrayObjectAnimator = context.obtainStyledAttributes(attrs, - R.styleable.PropertyAnimator); - } - - if (anim == null) { - anim = new ValueAnimator(); - } - - parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); - - final int resID = - arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); - if (resID > 0) { - anim.setInterpolator(InterpolatorInflater.loadInterpolator(context, resID)); - } - - arrayAnimator.recycle(); - if (arrayObjectAnimator != null) { - arrayObjectAnimator.recycle(); - } - - return anim; - } -} diff --git a/app/src/main/java/com/hippo/vectorold/animation/InterpolatorInflater.java b/app/src/main/java/com/hippo/vectorold/animation/InterpolatorInflater.java deleted file mode 100644 index e79cd5135..000000000 --- a/app/src/main/java/com/hippo/vectorold/animation/InterpolatorInflater.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2015 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.vectorold.animation; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.XmlResourceParser; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Xml; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.AnticipateInterpolator; -import android.view.animation.AnticipateOvershootInterpolator; -import android.view.animation.BounceInterpolator; -import android.view.animation.CycleInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; -import android.view.animation.OvershootInterpolator; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; - -public class InterpolatorInflater { - - /** - * Loads an {@link Interpolator} object from a resource - * - * @param context The Context - * @param id The resource id of the animation to load - * @return The interpolator object reference by the specified id - * @throws Resources.NotFoundException - */ - public static Interpolator loadInterpolator(Context context, int id) throws Resources.NotFoundException { - XmlResourceParser parser = null; - try { - parser = context.getResources().getAnimation(id); - return createInterpolatorFromXml(context, parser); - } catch (XmlPullParserException ex) { - Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } finally { - if (parser != null) - parser.close(); - } - - } - - private static Interpolator createInterpolatorFromXml(Context context, XmlPullParser parser) - throws XmlPullParserException, IOException { - - Interpolator interpolator = null; - - // Make sure we are on a start tag. - int type; - int depth = parser.getDepth(); - - while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { - - if (type != XmlPullParser.START_TAG) { - continue; - } - - AttributeSet attrs = Xml.asAttributeSet(parser); - - String name = parser.getName(); - - if (name.equals("linearInterpolator")) { - interpolator = new LinearInterpolator(); - } else if (name.equals("accelerateInterpolator")) { - interpolator = new AccelerateInterpolator(context, attrs); - } else if (name.equals("decelerateInterpolator")) { - interpolator = new DecelerateInterpolator(context, attrs); - } else if (name.equals("accelerateDecelerateInterpolator")) { - interpolator = new AccelerateDecelerateInterpolator(); - } else if (name.equals("cycleInterpolator")) { - interpolator = new CycleInterpolator(context, attrs); - } else if (name.equals("anticipateInterpolator")) { - interpolator = new AnticipateInterpolator(context, attrs); - } else if (name.equals("overshootInterpolator")) { - interpolator = new OvershootInterpolator(context, attrs); - } else if (name.equals("anticipateOvershootInterpolator")) { - interpolator = new AnticipateOvershootInterpolator(context, attrs); - } else if (name.equals("bounceInterpolator")) { - interpolator = new BounceInterpolator(); - } else if (name.equals("pathInterpolator")) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - interpolator = new PathInterpolator(context, attrs); - } else { - interpolator = new android.view.animation.PathInterpolator(context, attrs); - } - } else { - throw new RuntimeException("Unknown interpolator name: " + parser.getName()); - } - - } - - return interpolator; - } -} diff --git a/app/src/main/java/com/hippo/vectorold/animation/PathInterpolator.java b/app/src/main/java/com/hippo/vectorold/animation/PathInterpolator.java deleted file mode 100644 index ebb4f5aee..000000000 --- a/app/src/main/java/com/hippo/vectorold/animation/PathInterpolator.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.vectorold.animation; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.Resources.Theme; -import android.content.res.TypedArray; -import android.graphics.Path; -import android.graphics.PathMeasure; -import android.util.AttributeSet; -import android.view.InflateException; -import android.view.animation.Interpolator; - -import com.hippo.ehviewer.R; -import com.hippo.vectorold.util.PathParser; - -/** - * An interpolator that can traverse a Path that extends from Point - * (0, 0) to (1, 1). The x coordinate along the Path - * is the input value and the output is the y coordinate of the line at that point. - * This means that the Path must conform to a function y = f(x). - * - *

The Path must not have gaps in the x direction and must not - * loop back on itself such that there can be two points sharing the same x coordinate. - * It is alright to have a disjoint line in the vertical direction:

- *

- *     Path path = new Path();
- *     path.lineTo(0.25f, 0.25f);
- *     path.moveTo(0.25f, 0.5f);
- *     path.lineTo(1f, 1f);
- * 

- */ -public class PathInterpolator implements Interpolator { - - // This governs how accurate the approximation of the Path is. - private static final float PRECISION = 0.002f; - - private float[] mX; // x coordinates in the line - - private float[] mY; // y coordinates in the line - - /** - * Create an interpolator for an arbitrary Path. The Path - * must begin at (0, 0) and end at (1, 1). - * - * @param path The Path to use to make the line representing the interpolator. - */ - public PathInterpolator(Path path) { - initPath(path); - } - - /** - * Create an interpolator for a quadratic Bezier curve. The end points - * (0, 0) and (1, 1) are assumed. - * - * @param controlX The x coordinate of the quadratic Bezier control point. - * @param controlY The y coordinate of the quadratic Bezier control point. - */ - public PathInterpolator(float controlX, float controlY) { - initQuad(controlX, controlY); - } - - /** - * Create an interpolator for a cubic Bezier curve. The end points - * (0, 0) and (1, 1) are assumed. - * - * @param controlX1 The x coordinate of the first control point of the cubic Bezier. - * @param controlY1 The y coordinate of the first control point of the cubic Bezier. - * @param controlX2 The x coordinate of the second control point of the cubic Bezier. - * @param controlY2 The y coordinate of the second control point of the cubic Bezier. - */ - public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2) { - initCubic(controlX1, controlY1, controlX2, controlY2); - } - - public PathInterpolator(Context context, AttributeSet attrs) { - this(context.getResources(), context.getTheme(), attrs); - } - - public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) { - TypedArray a; - if (theme != null) { - a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0); - } else { - a = res.obtainAttributes(attrs, R.styleable.PathInterpolator); - } - parseInterpolatorFromTypeArray(a); - a.recycle(); - } - - private void parseInterpolatorFromTypeArray(TypedArray a) { - // If there is pathData defined in the xml file, then the controls points - // will be all coming from pathData. - if (a.hasValue(R.styleable.PathInterpolator_pathData)) { - String pathData = a.getString(R.styleable.PathInterpolator_pathData); - Path path = PathParser.createPathFromPathData(pathData); - if (path == null) { - throw new InflateException("The path is null, which is created" - + " from " + pathData); - } - initPath(path); - } else { - if (!a.hasValue(R.styleable.PathInterpolator_controlX1)) { - throw new InflateException("pathInterpolator requires the controlX1 attribute"); - } else if (!a.hasValue(R.styleable.PathInterpolator_controlY1)) { - throw new InflateException("pathInterpolator requires the controlY1 attribute"); - } - float x1 = a.getFloat(R.styleable.PathInterpolator_controlX1, 0); - float y1 = a.getFloat(R.styleable.PathInterpolator_controlY1, 0); - - boolean hasX2 = a.hasValue(R.styleable.PathInterpolator_controlX2); - boolean hasY2 = a.hasValue(R.styleable.PathInterpolator_controlY2); - - if (hasX2 != hasY2) { - throw new InflateException( - "pathInterpolator requires both controlX2 and controlY2 for cubic Beziers."); - } - - if (!hasX2) { - initQuad(x1, y1); - } else { - float x2 = a.getFloat(R.styleable.PathInterpolator_controlX2, 0); - float y2 = a.getFloat(R.styleable.PathInterpolator_controlY2, 0); - initCubic(x1, y1, x2, y2); - } - } - } - - private void initQuad(float controlX, float controlY) { - Path path = new Path(); - path.moveTo(0, 0); - path.quadTo(controlX, controlY, 1f, 1f); - initPath(path); - } - - private void initCubic(float x1, float y1, float x2, float y2) { - Path path = new Path(); - path.moveTo(0, 0); - path.cubicTo(x1, y1, x2, y2, 1f, 1f); - initPath(path); - } - - private void initPath(Path path) { - final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); - - final float pathLength = pathMeasure.getLength(); - final int numPoints = (int) (pathLength / PRECISION) + 1; - - mX = new float[numPoints]; - mY = new float[numPoints]; - - final float[] position = new float[2]; - for (int i = 0; i < numPoints; ++i) { - final float distance = (i * pathLength) / (numPoints - 1); - pathMeasure.getPosTan(distance, position, null /* tangent */); - - mX[i] = position[0]; - mY[i] = position[1]; - } - } - - /** - * Using the line in the Path in this interpolator that can be described as - * y = f(x), finds the y coordinate of the line given t - * as the x coordinate. Values less than 0 will always return 0 and values greater - * than 1 will always return 1. - * - * @param t Treated as the x coordinate along the line. - * @return The y coordinate of the Path along the line where x = t. - * @see Interpolator#getInterpolation(float) - */ - @Override - public float getInterpolation(float t) { - if (t <= 0) { - return 0; - } else if (t >= 1) { - return 1; - } - // Do a binary search for the correct x to interpolate between. - int startIndex = 0; - int endIndex = mX.length - 1; - - while (endIndex - startIndex > 1) { - int midIndex = (startIndex + endIndex) / 2; - if (t < mX[midIndex]) { - endIndex = midIndex; - } else { - startIndex = midIndex; - } - } - - float xRange = mX[endIndex] - mX[startIndex]; - if (xRange == 0) { - return mY[startIndex]; - } - - float tInRange = t - mX[startIndex]; - float fraction = tInRange / xRange; - - float startY = mY[startIndex]; - float endY = mY[endIndex]; - return startY + (fraction * (endY - startY)); - } -} diff --git a/app/src/main/java/com/hippo/vectorold/content/VectorContext.java b/app/src/main/java/com/hippo/vectorold/content/VectorContext.java deleted file mode 100644 index 0bc1ab2d2..000000000 --- a/app/src/main/java/com/hippo/vectorold/content/VectorContext.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2015 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.vectorold.content; - -import android.content.Context; -import android.content.ContextWrapper; -import android.content.res.Resources; -import android.content.res.VectorResources; -import android.os.Build; - -public class VectorContext extends ContextWrapper { - - private VectorResources mVectorResources; - - public VectorContext(Context base) { - super(base); - } - - @Override - public Resources getResources() { - final Resources superResources = super.getResources(); - if (mVectorResources == null || mVectorResources.isBase(superResources)) { - mVectorResources = new VectorResources(this, superResources); - } - return mVectorResources; - } - - /** - * In {@link android.content.ContextWrapper#attachBaseContext(Context)}, - * do super.attachBaseContext(Vector.wrapContext(newBase));. - * - * @param context the context - * @return new context - */ - public static Context wrapContext(Context context) { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? new VectorContext(context) : context; - } -} diff --git a/app/src/main/java/com/hippo/vectorold/drawable/AnimatedVectorDrawable.java b/app/src/main/java/com/hippo/vectorold/drawable/AnimatedVectorDrawable.java deleted file mode 100644 index f69194055..000000000 --- a/app/src/main/java/com/hippo/vectorold/drawable/AnimatedVectorDrawable.java +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.hippo.vectorold.drawable; - -import android.animation.Animator; -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.Drawable; -import android.support.v4.util.ArrayMap; -import android.util.AttributeSet; -import android.util.Log; - -import com.hippo.vectorold.animation.AnimatorInflater; -import com.hippo.ehviewer.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * This class uses {@link android.animation.ObjectAnimator} and - * {@link android.animation.AnimatorSet} to animate the properties of a - * {@link android.graphics.drawable.VectorDrawable} to create an animated drawable. - *

- * AnimatedVectorDrawable are normally defined as 3 separate XML files. - *

- *

- * First is the XML file for {@link android.graphics.drawable.VectorDrawable}. - * Note that we allow the animation happen on the group's attributes and path's - * attributes, which requires they are uniquely named in this xml file. Groups - * and paths without animations do not need names. - *

- *
  • Here is a simple VectorDrawable in this vectordrawable.xml file. - *
    - * <vector xmlns:android="http://schemas.android.com/apk/res/android"
    - *     android:height="64dp"
    - *     android:width="64dp"
    - *     android:viewportHeight="600"
    - *     android:viewportWidth="600" >
    - *     <group
    - *         android:name="rotationGroup"
    - *         android:pivotX="300.0"
    - *         android:pivotY="300.0"
    - *         android:rotation="45.0" >
    - *         <path
    - *             android:name="v"
    - *             android:fillColor="#000000"
    - *             android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    - *     </group>
    - * </vector>
    - * 
  • - *

    - * Second is the AnimatedVectorDrawable's xml file, which defines the target - * VectorDrawable, the target paths and groups to animate, the properties of the - * path and group to animate and the animations defined as the ObjectAnimators - * or AnimatorSets. - *

    - *
  • Here is a simple AnimatedVectorDrawable defined in this avd.xml file. - * Note how we use the names to refer to the groups and paths in the vectordrawable.xml. - *
    - * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    - *   android:drawable="@drawable/vectordrawable" >
    - *     <target
    - *         android:name="rotationGroup"
    - *         android:animation="@anim/rotation" />
    - *     <target
    - *         android:name="v"
    - *         android:animation="@anim/path_morph" />
    - * </animated-vector>
    - * 
  • - *

    - * Last is the Animator xml file, which is the same as a normal ObjectAnimator - * or AnimatorSet. - * To complete this example, here are the 2 animator files used in avd.xml: - * rotation.xml and path_morph.xml. - *

    - *
  • Here is the rotation.xml, which will rotate the target group for 360 degrees. - *
    - * <objectAnimator
    - *     android:duration="6000"
    - *     android:propertyName="rotation"
    - *     android:valueFrom="0"
    - *     android:valueTo="360" />
    - * 
  • - *
  • Here is the path_morph.xml, which will morph the path from one shape to - * the other. Note that the paths must be compatible for morphing. - * In more details, the paths should have exact same length of commands , and - * exact same length of parameters for each commands. - * Note that the path string are better stored in strings.xml for reusing. - *
    - * <set xmlns:android="http://schemas.android.com/apk/res/android">
    - *     <objectAnimator
    - *         android:duration="3000"
    - *         android:propertyName="pathData"
    - *         android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
    - *         android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
    - *         android:valueType="pathType"/>
    - * </set>
    - * 
  • - * - * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable - * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name - * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_animation - */ -public class AnimatedVectorDrawable extends Drawable implements Animatable { - private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName(); - - private static final String ANIMATED_VECTOR = "animated-vector"; - private static final String TARGET = "target"; - - private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; - - private AnimatedVectorDrawableState mAnimatedVectorState; - - private boolean mMutated; - - public AnimatedVectorDrawable() { - mAnimatedVectorState = new AnimatedVectorDrawableState(null); - } - - private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) { - mAnimatedVectorState = new AnimatedVectorDrawableState(state); - } - - @Override - public Drawable mutate() { - if (!mMutated && super.mutate() == this) { - mAnimatedVectorState.mVectorDrawable.mutate(); - mMutated = true; - } - return this; - } - - @Override - public ConstantState getConstantState() { - mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations(); - return mAnimatedVectorState; - } - - @Override - public int getChangingConfigurations() { - return super.getChangingConfigurations() | mAnimatedVectorState.mChangingConfigurations; - } - - @Override - public void draw(Canvas canvas) { - mAnimatedVectorState.mVectorDrawable.draw(canvas); - if (isStarted()) { - invalidateSelf(); - } - } - - @Override - protected void onBoundsChange(Rect bounds) { - mAnimatedVectorState.mVectorDrawable.setBounds(bounds); - } - - @Override - protected boolean onStateChange(int[] state) { - return mAnimatedVectorState.mVectorDrawable.setState(state); - } - - @Override - protected boolean onLevelChange(int level) { - return mAnimatedVectorState.mVectorDrawable.setLevel(level); - } - - @Override - public int getAlpha() { - return mAnimatedVectorState.mVectorDrawable.getAlpha(); - } - - @Override - public void setAlpha(int alpha) { - mAnimatedVectorState.mVectorDrawable.setAlpha(alpha); - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter); - } - - @Override - public void setTintList(ColorStateList tint) { - mAnimatedVectorState.mVectorDrawable.setTintList(tint); - } - - @Override - public void setTintMode(PorterDuff.Mode tintMode) { - mAnimatedVectorState.mVectorDrawable.setTintMode(tintMode); - } - - @Override - public boolean setVisible(boolean visible, boolean restart) { - mAnimatedVectorState.mVectorDrawable.setVisible(visible, restart); - return super.setVisible(visible, restart); - } - - @Override - public boolean isStateful() { - return mAnimatedVectorState.mVectorDrawable.isStateful(); - } - - @Override - public int getOpacity() { - return mAnimatedVectorState.mVectorDrawable.getOpacity(); - } - - @Override - public int getIntrinsicWidth() { - return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth(); - } - - @Override - public int getIntrinsicHeight() { - return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight(); - } - - public void inflate(Context context, XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { - Resources res = context.getResources(); - int eventType = parser.getEventType(); - float pathErrorScale = 1; - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - final String tagName = parser.getName(); - if (ANIMATED_VECTOR.equals(tagName)) { - final TypedArray a = res.obtainAttributes(attrs, - R.styleable.AnimatedVectorDrawable); - int drawableRes = a.getResourceId( - R.styleable.AnimatedVectorDrawable_drawable, 0); - if (drawableRes != 0) { - VectorDrawable vectorDrawable =(VectorDrawable) res.getDrawable( - drawableRes).mutate(); - vectorDrawable.setAllowCaching(false); - pathErrorScale = vectorDrawable.getPixelSize(); - mAnimatedVectorState.mVectorDrawable = vectorDrawable; - } - a.recycle(); - } else if (TARGET.equals(tagName)) { - final TypedArray a = res.obtainAttributes(attrs, - R.styleable.AnimatedVectorDrawableTarget); - final String target = a.getString( - R.styleable.AnimatedVectorDrawableTarget_name); - - int id = a.getResourceId( - R.styleable.AnimatedVectorDrawableTarget_animation, 0); - if (id != 0) { - Animator objectAnimator = AnimatorInflater.loadAnimator(context, id, pathErrorScale); - setupAnimatorsForTarget(target, objectAnimator); - } - a.recycle(); - } - } - - eventType = parser.next(); - } - } - - private static class AnimatedVectorDrawableState extends ConstantState { - int mChangingConfigurations; - VectorDrawable mVectorDrawable; - ArrayList mAnimators; - ArrayMap mTargetNameMap; - - public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) { - if (copy != null) { - mChangingConfigurations = copy.mChangingConfigurations; - if (copy.mVectorDrawable != null) { - mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable(); - mVectorDrawable.mutate(); - mVectorDrawable.setAllowCaching(false); - mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds()); - } - if (copy.mAnimators != null) { - final int numAnimators = copy.mAnimators.size(); - mAnimators = new ArrayList<>(numAnimators); - mTargetNameMap = new ArrayMap<>(numAnimators); - for (int i = 0; i < numAnimators; ++i) { - Animator anim = copy.mAnimators.get(i); - Animator animClone = anim.clone(); - String targetName = copy.mTargetNameMap.get(anim); - Object targetObject = mVectorDrawable.getTargetByName(targetName); - animClone.setTarget(targetObject); - mAnimators.add(animClone); - mTargetNameMap.put(animClone, targetName); - } - } - } else { - mVectorDrawable = new VectorDrawable(); - } - } - - @Override - public Drawable newDrawable() { - return new AnimatedVectorDrawable(this, null); - } - - @Override - public Drawable newDrawable(Resources res) { - return new AnimatedVectorDrawable(this, res); - } - - @Override - public int getChangingConfigurations() { - return mChangingConfigurations; - } - } - - private void setupAnimatorsForTarget(String name, Animator animator) { - Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name); - animator.setTarget(target); - if (mAnimatedVectorState.mAnimators == null) { - mAnimatedVectorState.mAnimators = new ArrayList<>(); - mAnimatedVectorState.mTargetNameMap = new ArrayMap<>(); - } - mAnimatedVectorState.mAnimators.add(animator); - mAnimatedVectorState.mTargetNameMap.put(animator, name); - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.v(LOGTAG, "add animator for target " + name + " " + animator); - } - } - - @Override - public boolean isRunning() { - final ArrayList animators = mAnimatedVectorState.mAnimators; - final int size = animators.size(); - for (int i = 0; i < size; i++) { - final Animator animator = animators.get(i); - if (animator.isRunning()) { - return true; - } - } - return false; - } - - private boolean isStarted() { - final ArrayList animators = mAnimatedVectorState.mAnimators; - final int size = animators.size(); - for (int i = 0; i < size; i++) { - final Animator animator = animators.get(i); - if (animator.isStarted()) { - return true; - } - } - return false; - } - - @Override - public void start() { - final ArrayList animators = mAnimatedVectorState.mAnimators; - final int size = animators.size(); - for (int i = 0; i < size; i++) { - final Animator animator = animators.get(i); - if (!animator.isStarted()) { - animator.start(); - } - } - invalidateSelf(); - } - - @Override - public void stop() { - final ArrayList animators = mAnimatedVectorState.mAnimators; - final int size = animators.size(); - for (int i = 0; i < size; i++) { - final Animator animator = animators.get(i); - animator.end(); - } - } - - /** - * Reverses ongoing animations or starts pending animations in reverse. - *

    - * NOTE: Only works of all animations are ValueAnimators. - * @hide - */ - /* - public void reverse() { - final ArrayList animators = mAnimatedVectorState.mAnimators; - final int size = animators.size(); - for (int i = 0; i < size; i++) { - final Animator animator = animators.get(i); - if (animator.canReverse()) { - animator.reverse(); - } else { - Log.w(LOGTAG, "AnimatedVectorDrawable can't reverse()"); - } - } - } - */ - - /** - * @hide - */ - /* - public boolean canReverse() { - final ArrayList animators = mAnimatedVectorState.mAnimators; - final int size = animators.size(); - for (int i = 0; i < size; i++) { - final Animator animator = animators.get(i); - if (!animator.canReverse()) { - return false; - } - } - return true; - } - */ -} diff --git a/app/src/main/java/com/hippo/vectorold/drawable/VectorDrawable.java b/app/src/main/java/com/hippo/vectorold/drawable/VectorDrawable.java deleted file mode 100644 index 13b7933a6..000000000 --- a/app/src/main/java/com/hippo/vectorold/drawable/VectorDrawable.java +++ /dev/null @@ -1,1399 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.hippo.vectorold.drawable; - -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PathMeasure; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.Region; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.v4.util.ArrayMap; -import android.util.AttributeSet; -import android.util.Log; -import android.util.Xml; - -import com.hippo.ehviewer.R; -import com.hippo.vectorold.util.DrawableUtils; -import com.hippo.vectorold.util.PathParser; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Stack; - -/** - * This lets you create a drawable based on an XML vector graphic. It can be - * defined in an XML file with the <vector> element. - *

    - * The vector drawable has the following elements: - *

    - *

    <vector>
    - *
    - *
    Used to defined a vector drawable - *
    - *
    android:name
    - *
    Defines the name of this vector drawable.
    - *
    android:width
    - *
    Used to defined the intrinsic width of the drawable. - * This support all the dimension units, normally specified with dp.
    - *
    android:height
    - *
    Used to defined the intrinsic height the drawable. - * This support all the dimension units, normally specified with dp.
    - *
    android:viewportWidth
    - *
    Used to defined the width of the viewport space. Viewport is basically - * the virtual canvas where the paths are drawn on.
    - *
    android:viewportHeight
    - *
    Used to defined the height of the viewport space. Viewport is basically - * the virtual canvas where the paths are drawn on.
    - *
    android:tint
    - *
    The color to apply to the drawable as a tint. By default, no tint is applied.
    - *
    android:tintMode
    - *
    The Porter-Duff blending mode for the tint color. The default value is src_in.
    - *
    android:autoMirrored
    - *
    Indicates if the drawable needs to be mirrored when its layout direction is - * RTL (right-to-left).
    - *
    android:alpha
    - *
    The opacity of this drawable.
    - *
    - *
    - * - *
    - *
    <group>
    - *
    Defines a group of paths or subgroups, plus transformation information. - * The transformations are defined in the same coordinates as the viewport. - * And the transformations are applied in the order of scale, rotate then translate. - *
    - *
    android:name
    - *
    Defines the name of the group.
    - *
    android:rotation
    - *
    The degrees of rotation of the group.
    - *
    android:pivotX
    - *
    The X coordinate of the pivot for the scale and rotation of the group. - * This is defined in the viewport space.
    - *
    android:pivotY
    - *
    The Y coordinate of the pivot for the scale and rotation of the group. - * This is defined in the viewport space.
    - *
    android:scaleX
    - *
    The amount of scale on the X Coordinate.
    - *
    android:scaleY
    - *
    The amount of scale on the Y coordinate.
    - *
    android:translateX
    - *
    The amount of translation on the X coordinate. - * This is defined in the viewport space.
    - *
    android:translateY
    - *
    The amount of translation on the Y coordinate. - * This is defined in the viewport space.
    - *
    - *
    - * - *
    - *
    <path>
    - *
    Defines paths to be drawn. - *
    - *
    android:name
    - *
    Defines the name of the path.
    - *
    android:pathData
    - *
    Defines path string. This is using exactly same format as "d" attribute - * in the SVG's path data. This is defined in the viewport space.
    - *
    android:fillColor
    - *
    Defines the color to fill the path (none if not present).
    - *
    android:strokeColor
    - *
    Defines the color to draw the path outline (none if not present).
    - *
    android:strokeWidth
    - *
    The width a path stroke.
    - *
    android:strokeAlpha
    - *
    The opacity of a path stroke.
    - *
    android:fillAlpha
    - *
    The opacity to fill the path with.
    - *
    android:trimPathStart
    - *
    The fraction of the path to trim from the start, in the range from 0 to 1.
    - *
    android:trimPathEnd
    - *
    The fraction of the path to trim from the end, in the range from 0 to 1.
    - *
    android:trimPathOffset
    - *
    Shift trim region (allows showed region to include the start and end), in the range - * from 0 to 1.
    - *
    android:strokeLineCap
    - *
    Sets the linecap for a stroked path: butt, round, square.
    - *
    android:strokeLineJoin
    - *
    Sets the lineJoin for a stroked path: miter,round,bevel.
    - *
    android:strokeMiterLimit
    - *
    Sets the Miter limit for a stroked path.
    - *
    - *
    - * - *
    - *
    <clip-path>
    - *
    Defines path to be the current clip. - *
    - *
    android:name
    - *
    Defines the name of the clip path.
    - *
    android:pathData
    - *
    Defines clip path string. This is using exactly same format as "d" attribute - * in the SVG's path data.
    - *
    - *
    - *
  • Here is a simple VectorDrawable in this vectordrawable.xml file. - *
    - * <vector xmlns:android="http://schemas.android.com/apk/res/android"
    - *     android:height="64dp"
    - *     android:width="64dp"
    - *     android:viewportHeight="600"
    - *     android:viewportWidth="600" >
    - *     <group
    - *         android:name="rotationGroup"
    - *         android:pivotX="300.0"
    - *         android:pivotY="300.0"
    - *         android:rotation="45.0" >
    - *         <path
    - *             android:name="v"
    - *             android:fillColor="#000000"
    - *             android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    - *     </group>
    - * </vector>
    - * 
  • - */ - -public class VectorDrawable extends Drawable { - private static final String LOGTAG = VectorDrawable.class.getSimpleName(); - - private static final String SHAPE_CLIP_PATH = "clip-path"; - private static final String SHAPE_GROUP = "group"; - private static final String SHAPE_PATH = "path"; - private static final String SHAPE_VECTOR = "vector"; - - private static final int LINECAP_BUTT = 0; - private static final int LINECAP_ROUND = 1; - private static final int LINECAP_SQUARE = 2; - - private static final int LINEJOIN_MITER = 0; - private static final int LINEJOIN_ROUND = 1; - private static final int LINEJOIN_BEVEL = 2; - - private static final boolean DBG_VECTOR_DRAWABLE = false; - - private VectorDrawableState mVectorState; - - private PorterDuffColorFilter mTintFilter; - private ColorFilter mColorFilter; - - private boolean mMutated; - - // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise, - // caching the bitmap by default is allowed. - private boolean mAllowCaching = true; - - public VectorDrawable() { - mVectorState = new VectorDrawableState(); - } - - private VectorDrawable(@NonNull VectorDrawableState state, Resources res) { - mVectorState = state; - mTintFilter = DrawableUtils.updateTintFilter(this, mTintFilter, state.mTint, state.mTintMode); - } - - @Override - public Drawable mutate() { - if (!mMutated && super.mutate() == this) { - mVectorState = new VectorDrawableState(mVectorState); - mMutated = true; - } - return this; - } - - Object getTargetByName(String name) { - return mVectorState.mVPathRenderer.mVGTargetsMap.get(name); - } - - @Override - public ConstantState getConstantState() { - mVectorState.mChangingConfigurations = getChangingConfigurations(); - return mVectorState; - } - - @Override - public void draw(Canvas canvas) { - final Rect bounds = getBounds(); - if (bounds.width() == 0 || bounds.height() == 0) { - // too small to draw - return; - } - - final int saveCount = canvas.save(); - final boolean needMirroring = needMirroring(); - - canvas.translate(bounds.left, bounds.top); - if (needMirroring) { - canvas.translate(bounds.width(), 0); - canvas.scale(-1.0f, 1.0f); - } - - // Color filters always override tint filters. - final ColorFilter colorFilter = mColorFilter == null ? mTintFilter : mColorFilter; - - if (!mAllowCaching) { - // AnimatedVectorDrawable - if (!mVectorState.hasTranslucentRoot()) { - mVectorState.mVPathRenderer.draw( - canvas, bounds.width(), bounds.height(), colorFilter); - } else { - mVectorState.createCachedBitmapIfNeeded(bounds); - mVectorState.updateCachedBitmap(bounds); - mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter); - } - } else { - // Static Vector Drawable case. - mVectorState.createCachedBitmapIfNeeded(bounds); - if (!mVectorState.canReuseCache()) { - mVectorState.updateCachedBitmap(bounds); - mVectorState.updateCacheStates(); - } - mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter); - } - - canvas.restoreToCount(saveCount); - } - - @Override - public int getAlpha() { - return mVectorState.mVPathRenderer.getRootAlpha(); - } - - @Override - public void setAlpha(int alpha) { - if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) { - mVectorState.mVPathRenderer.setRootAlpha(alpha); - invalidateSelf(); - } - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - mColorFilter = colorFilter; - invalidateSelf(); - } - - @Override - public void setTintList(ColorStateList tint) { - final VectorDrawableState state = mVectorState; - if (state.mTint != tint) { - state.mTint = tint; - mTintFilter = DrawableUtils.updateTintFilter(this, mTintFilter, tint, state.mTintMode); - invalidateSelf(); - } - } - - @Override - public void setTintMode(Mode tintMode) { - final VectorDrawableState state = mVectorState; - if (state.mTintMode != tintMode) { - state.mTintMode = tintMode; - mTintFilter = DrawableUtils.updateTintFilter(this, mTintFilter, state.mTint, tintMode); - invalidateSelf(); - } - } - - @Override - public boolean isStateful() { - return super.isStateful() || (mVectorState != null && mVectorState.mTint != null - && mVectorState.mTint.isStateful()); - } - - @Override - protected boolean onStateChange(int[] stateSet) { - final VectorDrawableState state = mVectorState; - if (state.mTint != null && state.mTintMode != null) { - mTintFilter = DrawableUtils.updateTintFilter(this, mTintFilter, state.mTint, state.mTintMode); - invalidateSelf(); - return true; - } - return false; - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public int getIntrinsicWidth() { - return (int) mVectorState.mVPathRenderer.mBaseWidth; - } - - @Override - public int getIntrinsicHeight() { - return (int) mVectorState.mVPathRenderer.mBaseHeight; - } - - /** - * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension. - * This is used to calculate the path animation accuracy. - */ - public float getPixelSize() { - if (mVectorState == null || mVectorState.mVPathRenderer == null || - mVectorState.mVPathRenderer.mBaseWidth == 0 || - mVectorState.mVPathRenderer.mBaseHeight == 0 || - mVectorState.mVPathRenderer.mViewportHeight == 0 || - mVectorState.mVPathRenderer.mViewportWidth == 0) { - return 1; // fall back to 1:1 pixel mapping. - } - float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth; - float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight; - float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth; - float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight; - float scaleX = viewportWidth / intrinsicWidth; - float scaleY = viewportHeight / intrinsicHeight; - return Math.min(scaleX, scaleY); - } - - /** @hide */ - public static VectorDrawable create(Resources resources, int rid) { - try { - final XmlPullParser parser = resources.getXml(rid); - final AttributeSet attrs = Xml.asAttributeSet(parser); - int type; - while ((type=parser.next()) != XmlPullParser.START_TAG && - type != XmlPullParser.END_DOCUMENT) { - // Empty loop - } - if (type != XmlPullParser.START_TAG) { - throw new XmlPullParserException("No start tag found"); - } - - final VectorDrawable drawable = new VectorDrawable(); - drawable.inflate(resources, parser, attrs); - - return drawable; - } catch (XmlPullParserException e) { - Log.e(LOGTAG, "parser error", e); - } catch (IOException e) { - Log.e(LOGTAG, "parser error", e); - } - return null; - } - - private static int applyAlpha(int color, float alpha) { - int alphaBytes = Color.alpha(color); - color &= 0x00FFFFFF; - color |= ((int) (alphaBytes * alpha)) << 24; - return color; - } - - @Override - public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { - final VectorDrawableState state = mVectorState; - final VPathRenderer pathRenderer = new VPathRenderer(); - state.mVPathRenderer = pathRenderer; - - final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable); - updateStateFromTypedArray(a); - a.recycle(); - - state.mCacheDirty = true; - inflateInternal(res, parser, attrs); - - mTintFilter = DrawableUtils.updateTintFilter(this, mTintFilter, state.mTint, state.mTintMode); - } - - private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { - final VectorDrawableState state = mVectorState; - final VPathRenderer pathRenderer = state.mVPathRenderer; - - // Account for any configuration changes. - state.mChangingConfigurations |= 0; //a.getChangingConfigurations(); - - final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1); - if (tintMode != -1) { - state.mTintMode = DrawableUtils.parseTintMode(tintMode, Mode.SRC_IN); - } - - final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint); - if (tint != null) { - state.mTint = tint; - } - - state.mAutoMirrored = a.getBoolean( - R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored); - - pathRenderer.mViewportWidth = a.getFloat( - R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth); - pathRenderer.mViewportHeight = a.getFloat( - R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight); - - if (pathRenderer.mViewportWidth <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - " tag requires viewportWidth > 0"); - } else if (pathRenderer.mViewportHeight <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - " tag requires viewportHeight > 0"); - } - - pathRenderer.mBaseWidth = a.getDimension( - R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth); - pathRenderer.mBaseHeight = a.getDimension( - R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight); - - if (pathRenderer.mBaseWidth <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - " tag requires width > 0"); - } else if (pathRenderer.mBaseHeight <= 0) { - throw new XmlPullParserException(a.getPositionDescription() + - " tag requires height > 0"); - } - - final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha, - pathRenderer.getAlpha()); - pathRenderer.setAlpha(alphaInFloat); - - final String name = a.getString(R.styleable.VectorDrawable_name); - if (name != null) { - pathRenderer.mRootName = name; - pathRenderer.mVGTargetsMap.put(name, pathRenderer); - } - } - - private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs) - throws XmlPullParserException, IOException { - final VectorDrawableState state = mVectorState; - final VPathRenderer pathRenderer = state.mVPathRenderer; - boolean noPathTag = true; - - // Use a stack to help to build the group tree. - // The top of the stack is always the current group. - final Stack groupStack = new Stack(); - groupStack.push(pathRenderer.mRootGroup); - - int eventType = parser.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - final String tagName = parser.getName(); - final VGroup currentGroup = groupStack.peek(); - - if (SHAPE_PATH.equals(tagName)) { - final VFullPath path = new VFullPath(); - path.inflate(res, attrs); - currentGroup.mChildren.add(path); - if (path.getPathName() != null) { - pathRenderer.mVGTargetsMap.put(path.getPathName(), path); - } - noPathTag = false; - state.mChangingConfigurations |= path.mChangingConfigurations; - } else if (SHAPE_CLIP_PATH.equals(tagName)) { - final VClipPath path = new VClipPath(); - path.inflate(res, attrs); - currentGroup.mChildren.add(path); - if (path.getPathName() != null) { - pathRenderer.mVGTargetsMap.put(path.getPathName(), path); - } - state.mChangingConfigurations |= path.mChangingConfigurations; - } else if (SHAPE_GROUP.equals(tagName)) { - VGroup newChildGroup = new VGroup(); - newChildGroup.inflate(res, attrs); - currentGroup.mChildren.add(newChildGroup); - groupStack.push(newChildGroup); - if (newChildGroup.getGroupName() != null) { - pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(), - newChildGroup); - } - state.mChangingConfigurations |= newChildGroup.mChangingConfigurations; - } - } else if (eventType == XmlPullParser.END_TAG) { - final String tagName = parser.getName(); - if (SHAPE_GROUP.equals(tagName)) { - groupStack.pop(); - } - } - eventType = parser.next(); - } - - // Print the tree out for debug. - if (DBG_VECTOR_DRAWABLE) { - printGroupTree(pathRenderer.mRootGroup, 0); - } - - if (noPathTag) { - final StringBuffer tag = new StringBuffer(); - - if (tag.length() > 0) { - tag.append(" or "); - } - tag.append(SHAPE_PATH); - - throw new XmlPullParserException("no " + tag + " defined"); - } - } - - private void printGroupTree(VGroup currentGroup, int level) { - String indent = ""; - for (int i = 0; i < level; i++) { - indent += " "; - } - // Print the current node - Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName() - + " rotation is " + currentGroup.mRotate); - Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString()); - // Then print all the children groups - for (int i = 0; i < currentGroup.mChildren.size(); i++) { - Object child = currentGroup.mChildren.get(i); - if (child instanceof VGroup) { - printGroupTree((VGroup) child, level + 1); - } - } - } - - @Override - public int getChangingConfigurations() { - return super.getChangingConfigurations() | mVectorState.mChangingConfigurations; - } - - void setAllowCaching(boolean allowCaching) { - mAllowCaching = allowCaching; - } - - private boolean needMirroring() { - return isAutoMirrored(); - } - - @Override - public void setAutoMirrored(boolean mirrored) { - if (mVectorState.mAutoMirrored != mirrored) { - mVectorState.mAutoMirrored = mirrored; - invalidateSelf(); - } - } - - @Override - public boolean isAutoMirrored() { - return mVectorState.mAutoMirrored; - } - - private static class VectorDrawableState extends ConstantState { - int mChangingConfigurations; - VPathRenderer mVPathRenderer; - ColorStateList mTint = null; - Mode mTintMode = DrawableUtils.DEFAULT_TINT_MODE; - boolean mAutoMirrored; - - Bitmap mCachedBitmap; - ColorStateList mCachedTint; - Mode mCachedTintMode; - int mCachedRootAlpha; - boolean mCachedAutoMirrored; - boolean mCacheDirty; - - /** Temporary paint object used to draw cached bitmaps. */ - Paint mTempPaint; - - // Deep copy for mutate() or implicitly mutate. - public VectorDrawableState(VectorDrawableState copy) { - if (copy != null) { - mChangingConfigurations = copy.mChangingConfigurations; - mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); - if (copy.mVPathRenderer.mFillPaint != null) { - mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint); - } - if (copy.mVPathRenderer.mStrokePaint != null) { - mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint); - } - mTint = copy.mTint; - mTintMode = copy.mTintMode; - mAutoMirrored = copy.mAutoMirrored; - } - } - - public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter) { - // The bitmap's size is the same as the bounds. - final Paint p = getPaint(filter); - canvas.drawBitmap(mCachedBitmap, 0, 0, p); - } - - public boolean hasTranslucentRoot() { - return mVPathRenderer.getRootAlpha() < 255; - } - - /** - * @return null when there is no need for alpha paint. - */ - public Paint getPaint(ColorFilter filter) { - if (!hasTranslucentRoot() && filter == null) { - return null; - } - - if (mTempPaint == null) { - mTempPaint = new Paint(); - mTempPaint.setFilterBitmap(true); - } - mTempPaint.setAlpha(mVPathRenderer.getRootAlpha()); - mTempPaint.setColorFilter(filter); - return mTempPaint; - } - - public void updateCachedBitmap(Rect bounds) { - mCachedBitmap.eraseColor(Color.TRANSPARENT); - Canvas tmpCanvas = new Canvas(mCachedBitmap); - mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height(), null); - } - - public void createCachedBitmapIfNeeded(Rect bounds) { - if (mCachedBitmap == null || !canReuseBitmap(bounds.width(), - bounds.height())) { - mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), - Bitmap.Config.ARGB_8888); - mCacheDirty = true; - } - - } - - public boolean canReuseBitmap(int width, int height) { - if (width == mCachedBitmap.getWidth() - && height == mCachedBitmap.getHeight()) { - return true; - } - return false; - } - - public boolean canReuseCache() { - if (!mCacheDirty - && mCachedTint == mTint - && mCachedTintMode == mTintMode - && mCachedAutoMirrored == mAutoMirrored - && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) { - return true; - } - return false; - } - - public void updateCacheStates() { - // Use shallow copy here and shallow comparison in canReuseCache(), - // likely hit cache miss more, but practically not much difference. - mCachedTint = mTint; - mCachedTintMode = mTintMode; - mCachedRootAlpha = mVPathRenderer.getRootAlpha(); - mCachedAutoMirrored = mAutoMirrored; - mCacheDirty = false; - } - - public VectorDrawableState() { - mVPathRenderer = new VPathRenderer(); - } - - @Override - public Drawable newDrawable() { - return new VectorDrawable(this, null); - } - - @Override - public Drawable newDrawable(Resources res) { - return new VectorDrawable(this, res); - } - - @Override - public int getChangingConfigurations() { - return mChangingConfigurations; - } - } - - private static class VPathRenderer { - /* Right now the internal data structure is organized as a tree. - * Each node can be a group node, or a path. - * A group node can have groups or paths as children, but a path node has - * no children. - * One example can be: - * Root Group - * / | \ - * Group Path Group - * / \ | - * Path Path Path - * - */ - // Variables that only used temporarily inside the draw() call, so there - // is no need for deep copying. - private final Path mPath; - private final Path mRenderPath; - private static final Matrix IDENTITY_MATRIX = new Matrix(); - private final Matrix mFinalPathMatrix = new Matrix(); - - private Paint mStrokePaint; - private Paint mFillPaint; - private PathMeasure mPathMeasure; - - ///////////////////////////////////////////////////// - // Variables below need to be copied (deep copy if applicable) for mutation. - private int mChangingConfigurations; - private final VGroup mRootGroup; - float mBaseWidth = 0; - float mBaseHeight = 0; - float mViewportWidth = 0; - float mViewportHeight = 0; - int mRootAlpha = 0xFF; - String mRootName = null; - - final ArrayMap mVGTargetsMap = new ArrayMap(); - - public VPathRenderer() { - mRootGroup = new VGroup(); - mPath = new Path(); - mRenderPath = new Path(); - } - - public void setRootAlpha(int alpha) { - mRootAlpha = alpha; - } - - public int getRootAlpha() { - return mRootAlpha; - } - - // setAlpha() and getAlpha() are used mostly for animation purpose, since - // Animator like to use alpha from 0 to 1. - public void setAlpha(float alpha) { - setRootAlpha((int) (alpha * 255)); - } - - @SuppressWarnings("unused") - public float getAlpha() { - return getRootAlpha() / 255.0f; - } - - public VPathRenderer(VPathRenderer copy) { - mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap); - mPath = new Path(copy.mPath); - mRenderPath = new Path(copy.mRenderPath); - mBaseWidth = copy.mBaseWidth; - mBaseHeight = copy.mBaseHeight; - mViewportWidth = copy.mViewportWidth; - mViewportHeight = copy.mViewportHeight; - mChangingConfigurations = copy.mChangingConfigurations; - mRootAlpha = copy.mRootAlpha; - mRootName = copy.mRootName; - if (copy.mRootName != null) { - mVGTargetsMap.put(copy.mRootName, this); - } - } - - private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix, - Canvas canvas, int w, int h, ColorFilter filter) { - // Calculate current group's matrix by preConcat the parent's and - // and the current one on the top of the stack. - // Basically the Mfinal = Mviewport * M0 * M1 * M2; - // Mi the local matrix at level i of the group tree. - currentGroup.mStackedMatrix.set(currentMatrix); - - currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix); - - // Draw the group tree in the same order as the XML file. - for (int i = 0; i < currentGroup.mChildren.size(); i++) { - Object child = currentGroup.mChildren.get(i); - if (child instanceof VGroup) { - VGroup childGroup = (VGroup) child; - drawGroupTree(childGroup, currentGroup.mStackedMatrix, - canvas, w, h, filter); - } else if (child instanceof VPath) { - VPath childPath = (VPath) child; - drawPath(currentGroup, childPath, canvas, w, h, filter); - } - } - } - - public void draw(Canvas canvas, int w, int h, ColorFilter filter) { - // Travese the tree in pre-order to draw. - drawGroupTree(mRootGroup, IDENTITY_MATRIX, canvas, w, h, filter); - } - - private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h, - ColorFilter filter) { - final float scaleX = w / mViewportWidth; - final float scaleY = h / mViewportHeight; - final float minScale = Math.min(scaleX, scaleY); - - mFinalPathMatrix.set(vGroup.mStackedMatrix); - mFinalPathMatrix.postScale(scaleX, scaleY); - - vPath.toPath(mPath); - final Path path = mPath; - - mRenderPath.reset(); - - if (vPath.isClipPath()) { - mRenderPath.addPath(path, mFinalPathMatrix); - canvas.clipPath(mRenderPath, Region.Op.REPLACE); - } else { - VFullPath fullPath = (VFullPath) vPath; - if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) { - float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f; - float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f; - - if (mPathMeasure == null) { - mPathMeasure = new PathMeasure(); - } - mPathMeasure.setPath(mPath, false); - - float len = mPathMeasure.getLength(); - start = start * len; - end = end * len; - path.reset(); - if (start > end) { - mPathMeasure.getSegment(start, len, path, true); - mPathMeasure.getSegment(0f, end, path, true); - } else { - mPathMeasure.getSegment(start, end, path, true); - } - path.rLineTo(0, 0); // fix bug in measure - } - mRenderPath.addPath(path, mFinalPathMatrix); - - if (fullPath.mFillColor != Color.TRANSPARENT) { - if (mFillPaint == null) { - mFillPaint = new Paint(); - mFillPaint.setStyle(Paint.Style.FILL); - mFillPaint.setAntiAlias(true); - } - - final Paint fillPaint = mFillPaint; - fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha)); - fillPaint.setColorFilter(filter); - canvas.drawPath(mRenderPath, fillPaint); - } - - if (fullPath.mStrokeColor != Color.TRANSPARENT) { - if (mStrokePaint == null) { - mStrokePaint = new Paint(); - mStrokePaint.setStyle(Paint.Style.STROKE); - mStrokePaint.setAntiAlias(true); - } - - final Paint strokePaint = mStrokePaint; - if (fullPath.mStrokeLineJoin != null) { - strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin); - } - - if (fullPath.mStrokeLineCap != null) { - strokePaint.setStrokeCap(fullPath.mStrokeLineCap); - } - - strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit); - strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha)); - strokePaint.setColorFilter(filter); - strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale); - canvas.drawPath(mRenderPath, strokePaint); - } - } - } - } - - private static class VGroup { - // mStackedMatrix is only used temporarily when drawing, it combines all - // the parents' local matrices with the current one. - private final Matrix mStackedMatrix = new Matrix(); - - ///////////////////////////////////////////////////// - // Variables below need to be copied (deep copy if applicable) for mutation. - final ArrayList mChildren = new ArrayList(); - - private float mRotate = 0; - private float mPivotX = 0; - private float mPivotY = 0; - private float mScaleX = 1; - private float mScaleY = 1; - private float mTranslateX = 0; - private float mTranslateY = 0; - - // mLocalMatrix is updated based on the update of transformation information, - // either parsed from the XML or by animation. - private final Matrix mLocalMatrix = new Matrix(); - private int mChangingConfigurations; - private String mGroupName = null; - - public VGroup(VGroup copy, ArrayMap targetsMap) { - mRotate = copy.mRotate; - mPivotX = copy.mPivotX; - mPivotY = copy.mPivotY; - mScaleX = copy.mScaleX; - mScaleY = copy.mScaleY; - mTranslateX = copy.mTranslateX; - mTranslateY = copy.mTranslateY; - mGroupName = copy.mGroupName; - mChangingConfigurations = copy.mChangingConfigurations; - if (mGroupName != null) { - targetsMap.put(mGroupName, this); - } - - mLocalMatrix.set(copy.mLocalMatrix); - - final ArrayList children = copy.mChildren; - for (int i = 0; i < children.size(); i++) { - Object copyChild = children.get(i); - if (copyChild instanceof VGroup) { - VGroup copyGroup = (VGroup) copyChild; - mChildren.add(new VGroup(copyGroup, targetsMap)); - } else { - VPath newPath = null; - if (copyChild instanceof VFullPath) { - newPath = new VFullPath((VFullPath) copyChild); - } else if (copyChild instanceof VClipPath) { - newPath = new VClipPath((VClipPath) copyChild); - } else { - throw new IllegalStateException("Unknown object in the tree!"); - } - mChildren.add(newPath); - if (newPath.mPathName != null) { - targetsMap.put(newPath.mPathName, newPath); - } - } - } - } - - public VGroup() { - } - - public String getGroupName() { - return mGroupName; - } - - public Matrix getLocalMatrix() { - return mLocalMatrix; - } - - public void inflate(Resources res, AttributeSet attrs) { - final TypedArray a = res.obtainAttributes(attrs, - R.styleable.VectorDrawableGroup); - updateStateFromTypedArray(a); - a.recycle(); - } - - private void updateStateFromTypedArray(TypedArray a) { - // Account for any configuration changes. - mChangingConfigurations |= 0; //a.getChangingConfigurations(); - - mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); - mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); - mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); - mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX); - mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY); - mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX); - mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY); - - final String groupName = a.getString(R.styleable.VectorDrawableGroup_name); - if (groupName != null) { - mGroupName = groupName; - } - - updateLocalMatrix(); - } - - private void updateLocalMatrix() { - // The order we apply is the same as the - // RenderNode.cpp::applyViewPropertyTransforms(). - mLocalMatrix.reset(); - mLocalMatrix.postTranslate(-mPivotX, -mPivotY); - mLocalMatrix.postScale(mScaleX, mScaleY); - mLocalMatrix.postRotate(mRotate, 0, 0); - mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY); - } - - /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ - @SuppressWarnings("unused") - public float getRotation() { - return mRotate; - } - - @SuppressWarnings("unused") - public void setRotation(float rotation) { - if (rotation != mRotate) { - mRotate = rotation; - updateLocalMatrix(); - } - } - - @SuppressWarnings("unused") - public float getPivotX() { - return mPivotX; - } - - @SuppressWarnings("unused") - public void setPivotX(float pivotX) { - if (pivotX != mPivotX) { - mPivotX = pivotX; - updateLocalMatrix(); - } - } - - @SuppressWarnings("unused") - public float getPivotY() { - return mPivotY; - } - - @SuppressWarnings("unused") - public void setPivotY(float pivotY) { - if (pivotY != mPivotY) { - mPivotY = pivotY; - updateLocalMatrix(); - } - } - - @SuppressWarnings("unused") - public float getScaleX() { - return mScaleX; - } - - @SuppressWarnings("unused") - public void setScaleX(float scaleX) { - if (scaleX != mScaleX) { - mScaleX = scaleX; - updateLocalMatrix(); - } - } - - @SuppressWarnings("unused") - public float getScaleY() { - return mScaleY; - } - - @SuppressWarnings("unused") - public void setScaleY(float scaleY) { - if (scaleY != mScaleY) { - mScaleY = scaleY; - updateLocalMatrix(); - } - } - - @SuppressWarnings("unused") - public float getTranslateX() { - return mTranslateX; - } - - @SuppressWarnings("unused") - public void setTranslateX(float translateX) { - if (translateX != mTranslateX) { - mTranslateX = translateX; - updateLocalMatrix(); - } - } - - @SuppressWarnings("unused") - public float getTranslateY() { - return mTranslateY; - } - - @SuppressWarnings("unused") - public void setTranslateY(float translateY) { - if (translateY != mTranslateY) { - mTranslateY = translateY; - updateLocalMatrix(); - } - } - } - - /** - * Common Path information for clip path and normal path. - */ - private static class VPath { - protected PathParser.PathDataNode[] mNodes = null; - String mPathName; - int mChangingConfigurations; - - public VPath() { - // Empty constructor. - } - - public VPath(VPath copy) { - mPathName = copy.mPathName; - mChangingConfigurations = copy.mChangingConfigurations; - mNodes = PathParser.deepCopyNodes(copy.mNodes); - } - - public void toPath(Path path) { - path.reset(); - if (mNodes != null) { - PathParser.PathDataNode.nodesToPath(mNodes, path); - } - } - - public String getPathName() { - return mPathName; - } - - public boolean isClipPath() { - return false; - } - - /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ - @SuppressWarnings("unused") - public PathParser.PathDataNode[] getPathData() { - return mNodes; - } - - @SuppressWarnings("unused") - public void setPathData(PathParser.PathDataNode[] nodes) { - if (!PathParser.canMorph(mNodes, nodes)) { - // This should not happen in the middle of animation. - mNodes = PathParser.deepCopyNodes(nodes); - } else { - PathParser.updateNodes(mNodes, nodes); - } - } - } - - /** - * Clip path, which only has name and pathData. - */ - private static class VClipPath extends VPath { - public VClipPath() { - // Empty constructor. - } - - public VClipPath(VClipPath copy) { - super(copy); - } - - public void inflate(Resources r, AttributeSet attrs) { - final TypedArray a = r.obtainAttributes(attrs, - R.styleable.VectorDrawableClipPath); - updateStateFromTypedArray(a); - a.recycle(); - } - - private void updateStateFromTypedArray(TypedArray a) { - // Account for any configuration changes. - mChangingConfigurations |= 0; //a.getChangingConfigurations(); - - final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name); - if (pathName != null) { - mPathName = pathName; - } - - final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData); - if (pathData != null) { - mNodes = PathParser.createNodesFromPathData(pathData); - } - } - - @Override - public boolean isClipPath() { - return true; - } - } - - /** - * Normal path, which contains all the fill / paint information. - */ - private static class VFullPath extends VPath { - ///////////////////////////////////////////////////// - // Variables below need to be copied (deep copy if applicable) for mutation. - int mStrokeColor = Color.TRANSPARENT; - float mStrokeWidth = 0; - - int mFillColor = Color.TRANSPARENT; - float mStrokeAlpha = 1.0f; - int mFillRule; - float mFillAlpha = 1.0f; - float mTrimPathStart = 0; - float mTrimPathEnd = 1; - float mTrimPathOffset = 0; - - Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; - Paint.Join mStrokeLineJoin = Paint.Join.MITER; - float mStrokeMiterlimit = 4; - - public VFullPath() { - // Empty constructor. - } - - public VFullPath(VFullPath copy) { - super(copy); - - mStrokeColor = copy.mStrokeColor; - mStrokeWidth = copy.mStrokeWidth; - mStrokeAlpha = copy.mStrokeAlpha; - mFillColor = copy.mFillColor; - mFillRule = copy.mFillRule; - mFillAlpha = copy.mFillAlpha; - mTrimPathStart = copy.mTrimPathStart; - mTrimPathEnd = copy.mTrimPathEnd; - mTrimPathOffset = copy.mTrimPathOffset; - - mStrokeLineCap = copy.mStrokeLineCap; - mStrokeLineJoin = copy.mStrokeLineJoin; - mStrokeMiterlimit = copy.mStrokeMiterlimit; - } - - private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) { - switch (id) { - case LINECAP_BUTT: - return Paint.Cap.BUTT; - case LINECAP_ROUND: - return Paint.Cap.ROUND; - case LINECAP_SQUARE: - return Paint.Cap.SQUARE; - default: - return defValue; - } - } - - private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) { - switch (id) { - case LINEJOIN_MITER: - return Paint.Join.MITER; - case LINEJOIN_ROUND: - return Paint.Join.ROUND; - case LINEJOIN_BEVEL: - return Paint.Join.BEVEL; - default: - return defValue; - } - } - - public void inflate(Resources r, AttributeSet attrs) { - final TypedArray a = r.obtainAttributes(attrs, - R.styleable.VectorDrawablePath); - updateStateFromTypedArray(a); - a.recycle(); - } - - private void updateStateFromTypedArray(TypedArray a) { - // Account for any configuration changes. - mChangingConfigurations |= 0; //a.getChangingConfigurations(); - - final String pathName = a.getString(R.styleable.VectorDrawablePath_name); - if (pathName != null) { - mPathName = pathName; - } - - final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData); - if (pathData != null) { - mNodes = PathParser.createNodesFromPathData(pathData); - } - - mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor, - mFillColor); - mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, - mFillAlpha); - mStrokeLineCap = getStrokeLineCap(a.getInt( - R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); - mStrokeLineJoin = getStrokeLineJoin(a.getInt( - R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin); - mStrokeMiterlimit = a.getFloat( - R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit); - mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor, - mStrokeColor); - mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha, - mStrokeAlpha); - mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, - mStrokeWidth); - mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, - mTrimPathEnd); - mTrimPathOffset = a.getFloat( - R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset); - mTrimPathStart = a.getFloat( - R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); - } - - /* Setters and Getters, used by animator from AnimatedVectorDrawable. */ - @SuppressWarnings("unused") - int getStrokeColor() { - return mStrokeColor; - } - - @SuppressWarnings("unused") - void setStrokeColor(int strokeColor) { - mStrokeColor = strokeColor; - } - - @SuppressWarnings("unused") - float getStrokeWidth() { - return mStrokeWidth; - } - - @SuppressWarnings("unused") - void setStrokeWidth(float strokeWidth) { - mStrokeWidth = strokeWidth; - } - - @SuppressWarnings("unused") - float getStrokeAlpha() { - return mStrokeAlpha; - } - - @SuppressWarnings("unused") - void setStrokeAlpha(float strokeAlpha) { - mStrokeAlpha = strokeAlpha; - } - - @SuppressWarnings("unused") - int getFillColor() { - return mFillColor; - } - - @SuppressWarnings("unused") - void setFillColor(int fillColor) { - mFillColor = fillColor; - } - - @SuppressWarnings("unused") - float getFillAlpha() { - return mFillAlpha; - } - - @SuppressWarnings("unused") - void setFillAlpha(float fillAlpha) { - mFillAlpha = fillAlpha; - } - - @SuppressWarnings("unused") - float getTrimPathStart() { - return mTrimPathStart; - } - - @SuppressWarnings("unused") - void setTrimPathStart(float trimPathStart) { - mTrimPathStart = trimPathStart; - } - - @SuppressWarnings("unused") - float getTrimPathEnd() { - return mTrimPathEnd; - } - - @SuppressWarnings("unused") - void setTrimPathEnd(float trimPathEnd) { - mTrimPathEnd = trimPathEnd; - } - - @SuppressWarnings("unused") - float getTrimPathOffset() { - return mTrimPathOffset; - } - - @SuppressWarnings("unused") - void setTrimPathOffset(float trimPathOffset) { - mTrimPathOffset = trimPathOffset; - } - } -} diff --git a/app/src/main/java/com/hippo/vectorold/util/DrawableUtils.java b/app/src/main/java/com/hippo/vectorold/util/DrawableUtils.java deleted file mode 100644 index 9a6498dea..000000000 --- a/app/src/main/java/com/hippo/vectorold/util/DrawableUtils.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2015 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.vectorold.util; - -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Drawable; - -public class DrawableUtils { - - public static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; - - /** - * Ensures the tint filter is consistent with the current tint color and - * mode. - */ - public static PorterDuffColorFilter updateTintFilter(Drawable drawable, - PorterDuffColorFilter tintFilter, ColorStateList tint, - PorterDuff.Mode tintMode) { - if (tint == null || tintMode == null) { - return null; - } - - final int color = tint.getColorForState(drawable.getState(), Color.TRANSPARENT); - return new PorterDuffColorFilter(color, tintMode); - } - - /** - * Parses a {@link PorterDuff.Mode} from a tintMode - * attribute's enum value. - */ - public static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) { - switch (value) { - case 3: return PorterDuff.Mode.SRC_OVER; - case 5: return PorterDuff.Mode.SRC_IN; - case 9: return PorterDuff.Mode.SRC_ATOP; - case 14: return PorterDuff.Mode.MULTIPLY; - case 15: return PorterDuff.Mode.SCREEN; - case 16: return PorterDuff.Mode.ADD; - default: return defaultMode; - } - } -} diff --git a/app/src/main/java/com/hippo/vectorold/util/PathParser.java b/app/src/main/java/com/hippo/vectorold/util/PathParser.java deleted file mode 100644 index 178c542dd..000000000 --- a/app/src/main/java/com/hippo/vectorold/util/PathParser.java +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.hippo.vectorold.util; - -import android.graphics.Path; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * @hide - */ -public class PathParser { - static final String LOGTAG = PathParser.class.getSimpleName(); - - /** - * @param pathData The string representing a path, the same as "d" string in svg file. - * @return the generated Path object. - */ - public static Path createPathFromPathData(String pathData) { - Path path = new Path(); - PathDataNode[] nodes = createNodesFromPathData(pathData); - if (nodes != null) { - PathDataNode.nodesToPath(nodes, path); - return path; - } - return null; - } - - /** - * @param pathData The string representing a path, the same as "d" string in svg file. - * @return an array of the PathDataNode. - */ - public static PathDataNode[] createNodesFromPathData(String pathData) { - if (pathData == null) { - return null; - } - int start = 0; - int end = 1; - - ArrayList list = new ArrayList(); - while (end < pathData.length()) { - end = nextStart(pathData, end); - String s = pathData.substring(start, end).trim(); - if (s.length() > 0) { - float[] val = getFloats(s); - addNode(list, s.charAt(0), val); - } - - start = end; - end++; - } - if ((end - start) == 1 && start < pathData.length()) { - addNode(list, pathData.charAt(start), new float[0]); - } - return list.toArray(new PathDataNode[list.size()]); - } - - /** - * @param source The array of PathDataNode to be duplicated. - * @return a deep copy of the source. - */ - public static PathDataNode[] deepCopyNodes(PathDataNode[] source) { - if (source == null) { - return null; - } - PathDataNode[] copy = new PathDataNode[source.length]; - for (int i = 0; i < source.length; i ++) { - copy[i] = new PathDataNode(source[i]); - } - return copy; - } - - /** - * @param nodesFrom The source path represented in an array of PathDataNode - * @param nodesTo The target path represented in an array of PathDataNode - * @return whether the nodesFrom can morph into nodesTo - */ - public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) { - if (nodesFrom == null || nodesTo == null) { - return false; - } - - if (nodesFrom.length != nodesTo.length) { - return false; - } - - for (int i = 0; i < nodesFrom.length; i ++) { - if (nodesFrom[i].mType != nodesTo[i].mType - || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) { - return false; - } - } - return true; - } - - /** - * Update the target's data to match the source. - * Before calling this, make sure canMorph(target, source) is true. - * - * @param target The target path represented in an array of PathDataNode - * @param source The source path represented in an array of PathDataNode - */ - public static void updateNodes(PathDataNode[] target, PathDataNode[] source) { - for (int i = 0; i < source.length; i ++) { - target[i].mType = source[i].mType; - for (int j = 0; j < source[i].mParams.length; j ++) { - target[i].mParams[j] = source[i].mParams[j]; - } - } - } - - private static int nextStart(String s, int end) { - char c; - - while (end < s.length()) { - c = s.charAt(end); - if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { - return end; - } - end++; - } - return end; - } - - private static void addNode(ArrayList list, char cmd, float[] val) { - list.add(new PathDataNode(cmd, val)); - } - - private static class ExtractFloatResult { - // We need to return the position of the next separator and whether the - // next float starts with a '-'. - int mEndPosition; - boolean mEndWithNegSign; - } - - /** - * Parse the floats in the string. - * This is an optimized version of parseFloat(s.split(",|\\s")); - * - * @param s the string containing a command and list of floats - * @return array of floats - */ - private static float[] getFloats(String s) { - if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { - return new float[0]; - } - try { - float[] results = new float[s.length()]; - int count = 0; - int startPosition = 1; - int endPosition = 0; - - ExtractFloatResult result = new ExtractFloatResult(); - int totalLength = s.length(); - - // The startPosition should always be the first character of the - // current number, and endPosition is the character after the current - // number. - while (startPosition < totalLength) { - extract(s, startPosition, result); - endPosition = result.mEndPosition; - - if (startPosition < endPosition) { - results[count++] = Float.parseFloat( - s.substring(startPosition, endPosition)); - } - - if (result.mEndWithNegSign) { - // Keep the '-' sign with next number. - startPosition = endPosition; - } else { - startPosition = endPosition + 1; - } - } - return Arrays.copyOf(results, count); - } catch (NumberFormatException e) { - Log.e(LOGTAG, "error in parsing \"" + s + "\""); - throw e; - } - } - - /** - * Calculate the position of the next comma or space or negative sign - * @param s the string to search - * @param start the position to start searching - * @param result the result of the extraction, including the position of the - * the starting position of next number, whether it is ending with a '-'. - */ - private static void extract(String s, int start, ExtractFloatResult result) { - // Now looking for ' ', ',' or '-' from the start. - int currentIndex = start; - boolean foundSeparator = false; - result.mEndWithNegSign = false; - for (; currentIndex < s.length(); currentIndex++) { - char currentChar = s.charAt(currentIndex); - switch (currentChar) { - case ' ': - case ',': - foundSeparator = true; - break; - case '-': - if (currentIndex != start) { - foundSeparator = true; - result.mEndWithNegSign = true; - } - break; - } - if (foundSeparator) { - break; - } - } - // When there is nothing found, then we put the end position to the end - // of the string. - result.mEndPosition = currentIndex; - } - - /** - * Each PathDataNode represents one command in the "d" attribute of the svg - * file. - * An array of PathDataNode can represent the whole "d" attribute. - */ - public static class PathDataNode { - private char mType; - private float[] mParams; - - private PathDataNode(char type, float[] params) { - mType = type; - mParams = params; - } - - private PathDataNode(PathDataNode n) { - mType = n.mType; - mParams = Arrays.copyOf(n.mParams, n.mParams.length); - } - - /** - * Convert an array of PathDataNode to Path. - * - * @param node The source array of PathDataNode. - * @param path The target Path object. - */ - public static void nodesToPath(PathDataNode[] node, Path path) { - float[] current = new float[4]; - char previousCommand = 'm'; - for (int i = 0; i < node.length; i++) { - addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); - previousCommand = node[i].mType; - } - } - - /** - * The current PathDataNode will be interpolated between the - * nodeFrom and nodeTo according to the - * fraction. - * - * @param nodeFrom The start value as a PathDataNode. - * @param nodeTo The end value as a PathDataNode - * @param fraction The fraction to interpolate. - */ - public void interpolatePathDataNode(PathDataNode nodeFrom, - PathDataNode nodeTo, float fraction) { - for (int i = 0; i < nodeFrom.mParams.length; i++) { - mParams[i] = nodeFrom.mParams[i] * (1 - fraction) - + nodeTo.mParams[i] * fraction; - } - } - - private static void addCommand(Path path, float[] current, - char previousCmd, char cmd, float[] val) { - - int incr = 2; - float currentX = current[0]; - float currentY = current[1]; - float ctrlPointX = current[2]; - float ctrlPointY = current[3]; - float reflectiveCtrlPointX; - float reflectiveCtrlPointY; - - switch (cmd) { - case 'z': - case 'Z': - path.close(); - return; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - incr = 2; - break; - case 'h': - case 'H': - case 'v': - case 'V': - incr = 1; - break; - case 'c': - case 'C': - incr = 6; - break; - case 's': - case 'S': - case 'q': - case 'Q': - incr = 4; - break; - case 'a': - case 'A': - incr = 7; - break; - } - for (int k = 0; k < val.length; k += incr) { - switch (cmd) { - case 'm': // moveto - Start a new sub-path (relative) - path.rMoveTo(val[k + 0], val[k + 1]); - currentX += val[k + 0]; - currentY += val[k + 1]; - break; - case 'M': // moveto - Start a new sub-path - path.moveTo(val[k + 0], val[k + 1]); - currentX = val[k + 0]; - currentY = val[k + 1]; - break; - case 'l': // lineto - Draw a line from the current point (relative) - path.rLineTo(val[k + 0], val[k + 1]); - currentX += val[k + 0]; - currentY += val[k + 1]; - break; - case 'L': // lineto - Draw a line from the current point - path.lineTo(val[k + 0], val[k + 1]); - currentX = val[k + 0]; - currentY = val[k + 1]; - break; - case 'z': // closepath - Close the current subpath - case 'Z': // closepath - Close the current subpath - path.close(); - break; - case 'h': // horizontal lineto - Draws a horizontal line (relative) - path.rLineTo(val[k + 0], 0); - currentX += val[k + 0]; - break; - case 'H': // horizontal lineto - Draws a horizontal line - path.lineTo(val[k + 0], currentY); - currentX = val[k + 0]; - break; - case 'v': // vertical lineto - Draws a vertical line from the current point (r) - path.rLineTo(0, val[k + 0]); - currentY += val[k + 0]; - break; - case 'V': // vertical lineto - Draws a vertical line from the current point - path.lineTo(currentX, val[k + 0]); - currentY = val[k + 0]; - break; - case 'c': // curveto - Draws a cubic Bézier curve (relative) - path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], - val[k + 4], val[k + 5]); - - ctrlPointX = currentX + val[k + 2]; - ctrlPointY = currentY + val[k + 3]; - currentX += val[k + 4]; - currentY += val[k + 5]; - - break; - case 'C': // curveto - Draws a cubic Bézier curve - path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], - val[k + 4], val[k + 5]); - currentX = val[k + 4]; - currentY = val[k + 5]; - ctrlPointX = val[k + 2]; - ctrlPointY = val[k + 3]; - break; - case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) - reflectiveCtrlPointX = 0; - reflectiveCtrlPointY = 0; - if (previousCmd == 'c' || previousCmd == 's' - || previousCmd == 'C' || previousCmd == 'S') { - reflectiveCtrlPointX = currentX - ctrlPointX; - reflectiveCtrlPointY = currentY - ctrlPointY; - } - path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1], - val[k + 2], val[k + 3]); - - ctrlPointX = currentX + val[k + 0]; - ctrlPointY = currentY + val[k + 1]; - currentX += val[k + 2]; - currentY += val[k + 3]; - break; - case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) - reflectiveCtrlPointX = currentX; - reflectiveCtrlPointY = currentY; - if (previousCmd == 'c' || previousCmd == 's' - || previousCmd == 'C' || previousCmd == 'S') { - reflectiveCtrlPointX = 2 * currentX - ctrlPointX; - reflectiveCtrlPointY = 2 * currentY - ctrlPointY; - } - path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - ctrlPointX = val[k + 0]; - ctrlPointY = val[k + 1]; - currentX = val[k + 2]; - currentY = val[k + 3]; - break; - case 'q': // Draws a quadratic Bézier (relative) - path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - ctrlPointX = currentX + val[k + 0]; - ctrlPointY = currentY + val[k + 1]; - currentX += val[k + 2]; - currentY += val[k + 3]; - break; - case 'Q': // Draws a quadratic Bézier - path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - ctrlPointX = val[k + 0]; - ctrlPointY = val[k + 1]; - currentX = val[k + 2]; - currentY = val[k + 3]; - break; - case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) - reflectiveCtrlPointX = 0; - reflectiveCtrlPointY = 0; - if (previousCmd == 'q' || previousCmd == 't' - || previousCmd == 'Q' || previousCmd == 'T') { - reflectiveCtrlPointX = currentX - ctrlPointX; - reflectiveCtrlPointY = currentY - ctrlPointY; - } - path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1]); - ctrlPointX = currentX + reflectiveCtrlPointX; - ctrlPointY = currentY + reflectiveCtrlPointY; - currentX += val[k + 0]; - currentY += val[k + 1]; - break; - case 'T': // Draws a quadratic Bézier curve (reflective control point) - reflectiveCtrlPointX = currentX; - reflectiveCtrlPointY = currentY; - if (previousCmd == 'q' || previousCmd == 't' - || previousCmd == 'Q' || previousCmd == 'T') { - reflectiveCtrlPointX = 2 * currentX - ctrlPointX; - reflectiveCtrlPointY = 2 * currentY - ctrlPointY; - } - path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - val[k + 0], val[k + 1]); - ctrlPointX = reflectiveCtrlPointX; - ctrlPointY = reflectiveCtrlPointY; - currentX = val[k + 0]; - currentY = val[k + 1]; - break; - case 'a': // Draws an elliptical arc - // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) - drawArc(path, - currentX, - currentY, - val[k + 5] + currentX, - val[k + 6] + currentY, - val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3] != 0, - val[k + 4] != 0); - currentX += val[k + 5]; - currentY += val[k + 6]; - ctrlPointX = currentX; - ctrlPointY = currentY; - break; - case 'A': // Draws an elliptical arc - drawArc(path, - currentX, - currentY, - val[k + 5], - val[k + 6], - val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3] != 0, - val[k + 4] != 0); - currentX = val[k + 5]; - currentY = val[k + 6]; - ctrlPointX = currentX; - ctrlPointY = currentY; - break; - } - previousCmd = cmd; - } - current[0] = currentX; - current[1] = currentY; - current[2] = ctrlPointX; - current[3] = ctrlPointY; - } - - private static void drawArc(Path p, - float x0, - float y0, - float x1, - float y1, - float a, - float b, - float theta, - boolean isMoreThanHalf, - boolean isPositiveArc) { - - /* Convert rotation angle from degrees to radians */ - double thetaD = Math.toRadians(theta); - /* Pre-compute rotation matrix entries */ - double cosTheta = Math.cos(thetaD); - double sinTheta = Math.sin(thetaD); - /* Transform (x0, y0) and (x1, y1) into unit space */ - /* using (inverse) rotation, followed by (inverse) scale */ - double x0p = (x0 * cosTheta + y0 * sinTheta) / a; - double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; - double x1p = (x1 * cosTheta + y1 * sinTheta) / a; - double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; - - /* Compute differences and averages */ - double dx = x0p - x1p; - double dy = y0p - y1p; - double xm = (x0p + x1p) / 2; - double ym = (y0p + y1p) / 2; - /* Solve for intersecting unit circles */ - double dsq = dx * dx + dy * dy; - if (dsq == 0.0) { - Log.w(LOGTAG, " Points are coincident"); - return; /* Points are coincident */ - } - double disc = 1.0 / dsq - 1.0 / 4.0; - if (disc < 0.0) { - Log.w(LOGTAG, "Points are too far apart " + dsq); - float adjust = (float) (Math.sqrt(dsq) / 1.99999); - drawArc(p, x0, y0, x1, y1, a * adjust, - b * adjust, theta, isMoreThanHalf, isPositiveArc); - return; /* Points are too far apart */ - } - double s = Math.sqrt(disc); - double sdx = s * dx; - double sdy = s * dy; - double cx; - double cy; - if (isMoreThanHalf == isPositiveArc) { - cx = xm - sdy; - cy = ym + sdx; - } else { - cx = xm + sdy; - cy = ym - sdx; - } - - double eta0 = Math.atan2((y0p - cy), (x0p - cx)); - - double eta1 = Math.atan2((y1p - cy), (x1p - cx)); - - double sweep = (eta1 - eta0); - if (isPositiveArc != (sweep >= 0)) { - if (sweep > 0) { - sweep -= 2 * Math.PI; - } else { - sweep += 2 * Math.PI; - } - } - - cx *= a; - cy *= b; - double tcx = cx; - cx = cx * cosTheta - cy * sinTheta; - cy = tcx * sinTheta + cy * cosTheta; - - arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); - } - - /** - * Converts an arc to cubic Bezier segments and records them in p. - * - * @param p The target for the cubic Bezier segments - * @param cx The x coordinate center of the ellipse - * @param cy The y coordinate center of the ellipse - * @param a The radius of the ellipse in the horizontal direction - * @param b The radius of the ellipse in the vertical direction - * @param e1x E(eta1) x coordinate of the starting point of the arc - * @param e1y E(eta2) y coordinate of the starting point of the arc - * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane - * @param start The start angle of the arc on the ellipse - * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse - */ - private static void arcToBezier(Path p, - double cx, - double cy, - double a, - double b, - double e1x, - double e1y, - double theta, - double start, - double sweep) { - // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html - // and http://www.spaceroots.org/documents/ellipse/node22.html - - // Maximum of 45 degrees per cubic Bezier segment - int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); - - double eta1 = start; - double cosTheta = Math.cos(theta); - double sinTheta = Math.sin(theta); - double cosEta1 = Math.cos(eta1); - double sinEta1 = Math.sin(eta1); - double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); - double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); - - double anglePerSegment = sweep / numSegments; - for (int i = 0; i < numSegments; i++) { - double eta2 = eta1 + anglePerSegment; - double sinEta2 = Math.sin(eta2); - double cosEta2 = Math.cos(eta2); - double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); - double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); - double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; - double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; - double tanDiff2 = Math.tan((eta2 - eta1) / 2); - double alpha = - Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; - double q1x = e1x + alpha * ep1x; - double q1y = e1y + alpha * ep1y; - double q2x = e2x - alpha * ep2x; - double q2y = e2y - alpha * ep2y; - - p.cubicTo((float) q1x, - (float) q1y, - (float) q2x, - (float) q2y, - (float) e2x, - (float) e2y); - eta1 = eta2; - e1x = e2x; - e1y = e2y; - ep1x = ep2x; - ep1y = ep2y; - } - } - } -} diff --git a/app/src/main/res/values/vectorold_attrs.xml b/app/src/main/res/values/vectorold_attrs.xml deleted file mode 100644 index 42b1a8388..000000000 --- a/app/src/main/res/values/vectorold_attrs.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/settings.gradle b/settings.gradle index da52a68e0..790ceba2b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':unifile' +include ':app', ':unifile', ':vectorold' diff --git a/vectorold b/vectorold new file mode 160000 index 000000000..1a8e63bcb --- /dev/null +++ b/vectorold @@ -0,0 +1 @@ +Subproject commit 1a8e63bcb3a70c2a96e99e64716b98ca12c93804