Move vectorold to separated package

This commit is contained in:
seven332 committed 2015-05-22 19:28:44 +08:00
1 parent 104918ef82
commit 17625f9f97
17 files changed
+342 -1630

No files matched your search

@@ -23,8 +23,8 @@ import android.util.AttributeSet;
import android.util.TypedValue;
import android.util.Xml;
import com.hippo.drawable.AnimatedVectorDrawable;
import com.hippo.drawable.VectorDrawable;
import com.hippo.vectorold.drawable.AnimatedVectorDrawable;
import com.hippo.vectorold.drawable.VectorDrawable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -20,7 +20,7 @@ import android.content.Context;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.backends.okhttp.OkHttpImagePipelineConfigFactory;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.hippo.content.VectorContext;
import com.hippo.vectorold.content.VectorContext;
import com.hippo.ehviewer.network.EhOkHttpClient;
import com.hippo.ehviewer.util.Config;
import com.hippo.scene.SceneApplication;
@@ -26,7 +26,7 @@ import android.view.Gravity;
import android.view.View;
import android.widget.AdapterView;
import com.hippo.content.VectorContext;
import com.hippo.vectorold.content.VectorContext;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.scene.GalleryListScene;
@@ -1,641 +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
* 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.graphics;
import java.util.LinkedList;
import java.util.List;
public class JPath {
private List<PathAction> mActionList = new LinkedList<>();
/** startX, startY, length**/
private float[] mTemp = new float[2];
{
mTemp[0] = 0f;
mTemp[1] = 0f;
}
public void close() {
// Empty
}
/**
* Set the beginning of the next contour to the point (x,y).
*
* @param x The x-coordinate of the start of a new contour
* @param y The y-coordinate of the start of a new contour
*/
public void moveTo(float x, float y) {
mActionList.add(new MoveAction(x, y));
}
/**
* Set the beginning of the next contour relative to the last point on the
* previous contour. If there is no previous contour, this is treated the
* same as moveTo().
*
* @param dx The amount to add to the x-coordinate of the end of the
* previous contour, to specify the start of a new contour
* @param dy The amount to add to the y-coordinate of the end of the
* previous contour, to specify the start of a new contour
*/
public void rMoveTo(float dx, float dy) {
mActionList.add(new RMoveAction(dx, dy));
}
/**
* Add a line from the last point to the specified point (x,y).
* If no moveTo() call has been made for this contour, the first point is
* automatically set to (0,0).
*
* @param x The x-coordinate of the end of a line
* @param y The y-coordinate of the end of a line
*/
public void lineTo(float x, float y) {
mActionList.add(new LineToAction(x, y));
}
/**
* Same as lineTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx The amount to add to the x-coordinate of the previous point on
* this contour, to specify a line
* @param dy The amount to add to the y-coordinate of the previous point on
* this contour, to specify a line
*/
public void rLineTo(float dx, float dy) {
mActionList.add(new RLineToAction(dx, dy));
}
/**
* Add a quadratic bezier from the last point, approaching control point
* (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
* this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the control point on a quadratic curve
* @param y1 The y-coordinate of the control point on a quadratic curve
* @param x2 The x-coordinate of the end point on a quadratic curve
* @param y2 The y-coordinate of the end point on a quadratic curve
*/
public void quadTo(float x1, float y1, float x2, float y2) {
mActionList.add(new QuadToAction(x1, y1, x2, y2));
}
/**
* Same as quadTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx1 The amount to add to the x-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dy1 The amount to add to the y-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dx2 The amount to add to the x-coordinate of the last point on
* this contour, for the end point of a quadratic curve
* @param dy2 The amount to add to the y-coordinate of the last point on
* this contour, for the end point of a quadratic curve
*/
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
mActionList.add(new RQuadToAction(dx1, dy1, dx2, dy2));
}
/**
* Add a cubic bezier from the last point, approaching control points
* (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
* made for this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the 1st control point on a cubic curve
* @param y1 The y-coordinate of the 1st control point on a cubic curve
* @param x2 The x-coordinate of the 2nd control point on a cubic curve
* @param y2 The y-coordinate of the 2nd control point on a cubic curve
* @param x3 The x-coordinate of the end point on a cubic curve
* @param y3 The y-coordinate of the end point on a cubic curve
*/
public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
mActionList.add(new CubicToAction(x1, y1, x2, y2, x3, y3));
}
/**
* Same as cubicTo, but the coordinates are considered relative to the
* current point on this contour. If there is no previous point, then a
* moveTo(0,0) is inserted automatically.
*/
public void rCubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
mActionList.add(new RCubicToAction(x1, y1, x2, y2, x3, y3));
}
/**
* Approximate the <code>Path</code> with a series of line segments.
* This returns float[] with the array containing point components.
* There are three components for each point, in order:
* <ul>
* <li>Fraction along the length of the path that the point resides</li>
* <li>The x coordinate of the point</li>
* <li>The y coordinate of the point</li>
* </ul>
* <p>Two points may share the same fraction along its length when there is
* a move action within the Path.</p>
*
* @param acceptableError The acceptable error for a line on the
* Path. Typically this would be 0.5 so that
* the error is less than half a pixel.
* @return An array of components for points approximating the Path.
*/
public float[] approximate(float acceptableError) {
PointMap pm = new PointMap();
for (PathAction pa : mActionList) {
pa.approximate(pm, mTemp, acceptableError);
}
return pm.generate();
}
/**
* Returns true if the path is empty (contains no lines or curves)
*
* @return true if the path is empty (contains no lines or curves)
*/
public boolean isEmpty() {
return mActionList.isEmpty();
}
/**
* Clear any lines and curves from the path, making it empty.
* This does NOT change the fill-type setting.
*/
public void reset() {
mActionList.clear();
}
private static final class PointMap {
private int size = 0;
private Link firstLink;
private Link lastLink;
float totalLength = 0f;
private static final class Link {
/** It is only for bezier **/
float t;
float x;
float y;
/** It should be Length first **/
float f = -1;
private Link previous, next;
Link(float t, float x, float y, float f, Link p, Link n) {
this.t = t;
this.x = x;
this.y = y;
this.f = f;
this.previous = p;
this.next = n;
}
}
public static final class Iterator {
final PointMap parent;
Link link;
private Iterator(PointMap p, Link l) {
parent = p;
link = l;
}
boolean hasNext() {
return link.next != null;
}
Iterator nextIterator() {
if (hasNext()) {
return new Iterator(parent, link.next);
} else {
return null;
}
}
// Move iterator to the new data
void addBefore(float t, float x, float y, float f) {
Link p = link.previous;
Link l = new Link(t, x, y, f, p, link);
link.previous = l;
p.next = l;
link = l;
parent.size++;
}
}
public void add(float t, float x, float y, float f) {
Link link = new Link(t, x, y, f, null, null);
if (lastLink != null) {
link.previous = lastLink;
lastLink.next = link;
}
lastLink = link;
if (firstLink == null) {
firstLink = link;
}
size++;
}
// Get a iterator at first data or null
public Iterator iterator() {
if (firstLink != null) {
return new Iterator(this, firstLink);
} else {
return null;
}
}
public Iterator lastIterator() {
if (lastLink != null) {
return new Iterator(this, lastLink);
} else {
return null;
}
}
public float[] generate() {
int index = 0;
float[] result = new float[size * 3];
for (Link link = firstLink; link != null; link = link.next) {
result[index++] = link.f / totalLength;
result[index++] = link.x;
result[index++] = link.y;
}
return result;
}
}
private abstract static class PathAction {
public abstract void approximate(PointMap pointMap, float[] startPoint, float acceptableError);
}
private static class MoveAction extends PathAction {
private float mX;
private float mY;
public MoveAction(float x, float y) {
mX = x;
mY = y;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
float x = mX;
float y = mY;
pointMap.add(0f, x, y, pointMap.totalLength);
startPoint[0] = x;
startPoint[1] = y;
}
}
private static class RMoveAction extends PathAction {
private float mDx;
private float mDy;
public RMoveAction(float dx, float dy) {
mDx = dx;
mDy = dy;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
float x = startPoint[0] + mDx;
float y = startPoint[1] + mDy;
pointMap.add(0f, x, y, pointMap.totalLength);
startPoint[0] = x;
startPoint[1] = y;
}
}
private static class LineToAction extends PathAction {
private float mX;
private float mY;
public LineToAction(float x, float y) {
mX = x;
mY = y;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
if (pointMap.size == 0) {
// No start point in map, just add it
pointMap.add(0f, startPoint[0], startPoint[1], 0f);
}
float x = mX;
float y = mY;
float length = dist(startPoint[0], startPoint[1], x, y) +
pointMap.totalLength;
pointMap.add(0f, x, y, length);
pointMap.totalLength = length;
startPoint[0] = x;
startPoint[1] = y;
}
}
private static class RLineToAction extends PathAction {
private float mDx;
private float mDy;
public RLineToAction(float dx, float dy) {
mDx = dx;
mDy = dy;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
if (pointMap.size == 0) {
// No start point in map, just add it
pointMap.add(0f, startPoint[0], startPoint[1], 0f);
}
float x = startPoint[0] + mDx;
float y = startPoint[1] + mDy;
float length = (float) Math.hypot(mDx, mDy) +
pointMap.totalLength;
pointMap.add(0f, x, y, length);
pointMap.totalLength = length;
startPoint[0] = x;
startPoint[1] = y;
}
}
private static class QuadToAction extends PathAction {
private float mX1;
private float mY1;
private float mX2;
private float mY2;
public QuadToAction(float x1, float y1, float x2, float y2) {
mX1 = x1;
mY1 = y1;
mX2 = x2;
mY2 = y2;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
float[] control = new float[]{
startPoint[0], startPoint[1],
mX1, mY1,
mX2, mY2
};
bezierApproximate(pointMap, control, acceptableError, false);
startPoint[0] = control[0];
startPoint[1] = control[1];
}
}
private static class RQuadToAction extends PathAction {
private float mDx1;
private float mDy1;
private float mDx2;
private float mDy2;
public RQuadToAction(float dx1, float dy1, float dx2, float dy2) {
mDx1 = dx1;
mDy1 = dy1;
mDx2 = dx2;
mDy2 = dy2;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
float startX = startPoint[0];
float startY = startPoint[1];
float[] control = new float[]{
startX, startY,
startX + mDx1, startY + mDy1,
startX + mDx2, startY + mDy2
};
bezierApproximate(pointMap, control, acceptableError, false);
startPoint[0] = control[0];
startPoint[1] = control[1];
}
}
private static class CubicToAction extends PathAction {
private float mX1;
private float mY1;
private float mX2;
private float mY2;
private float mX3;
private float mY3;
public CubicToAction(float x1, float y1, float x2, float y2, float x3, float y3) {
mX1 = x1;
mY1 = y1;
mX2 = x2;
mY2 = y2;
mX3 = x3;
mY3 = y3;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
float[] control = new float[]{
startPoint[0], startPoint[1],
mX1, mY1,
mX2, mY2,
mX3, mY3
};
bezierApproximate(pointMap, control, acceptableError, true);
startPoint[0] = control[0];
startPoint[1] = control[1];
}
}
private static class RCubicToAction extends PathAction {
private float mDx1;
private float mDy1;
private float mDx2;
private float mDy2;
private float mDx3;
private float mDy3;
public RCubicToAction(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) {
mDx1 = dx1;
mDy1 = dy1;
mDx2 = dx2;
mDy2 = dy2;
mDx3 = dx3;
mDy3 = dy3;
}
@Override
public void approximate(PointMap pointMap, float[] startPoint, float acceptableError) {
float startX = startPoint[0];
float startY = startPoint[1];
float[] control = new float[]{
startX, startY,
startX + mDx1, startY + mDy1,
startX + mDx2, startY + mDy2,
startX + mDx3, startY + mDy3,
};
bezierApproximate(pointMap, control, acceptableError, true);
startPoint[0] = control[0];
startPoint[1] = control[1];
}
}
// Divides Bezier curves until linear interpolation is very close to accurate, using
// errorSquared as a metric. Cubic Bezier curves can have an inflection point that improperly
// short-circuit subdivision. If you imagine an S shape, the top and bottom points being the
// starting and end points, linear interpolation would mark the center where the curve places
// the point. It is clearly not the case that we can linearly interpolate at that point.
// doubleCheckDivision forces a second examination between subdivisions to ensure that linear
// interpolation works.
private static void bezierApproximate(PointMap pointMap, float[] control,
float acceptableError, boolean isCubic) {
float errorSquared = acceptableError * acceptableError;
if (pointMap.size == 0) {
// No start point in map, just add it
pointMap.add(0f, control[0], control[1], 0f);
}
PointMap.Iterator iter = pointMap.lastIterator();
// Make sure start t is 0
iter.link.t = 0f;
// Add end point
if (isCubic) {
pointMap.add(1f, control[6], control[7], 0);
} else {
pointMap.add(1f, control[4], control[5], 0);
}
// Get next iterator
PointMap.Iterator next = iter.nextIterator();
boolean doubleCheckDivision = isCubic;
while (next != null) {
boolean needsSubdivision;
do {
PointMap.Link iterLink = iter.link;
PointMap.Link nextLink = next.link;
float midT = (iterLink.t + nextLink.t) / 2;
float midX = (iterLink.x + nextLink.x) / 2;
float midY = (iterLink.y + nextLink.y) / 2;
float midPointX = bezierX(midT, control, isCubic);
float midPointY = bezierY(midT, control, isCubic);
needsSubdivision = isOutOfErrorSquared(midX, midY, midPointX, midPointY, errorSquared);
if (!needsSubdivision && doubleCheckDivision) {
float quarterT = (iterLink.t + midT) / 2;
float quarterX = (iterLink.x + midPointX) / 2;
float quarterY = (iterLink.y + midPointY) / 2;
float quarterPointX = bezierX(quarterT, control, isCubic);
float quarterPointY = bezierY(quarterT, control, isCubic);
needsSubdivision = isOutOfErrorSquared(quarterX, quarterY, quarterPointX, quarterPointY, errorSquared);
if (needsSubdivision) {
// Found an inflection point. No need to double-check.
doubleCheckDivision = false;
}
}
if (needsSubdivision) {
// Add length soon
next.addBefore(midT, midPointX, midPointY, 0);
} else {
float length = dist(iterLink.x, iterLink.y, nextLink.x, nextLink.y);
iterLink.f = pointMap.totalLength;
pointMap.totalLength += length;
}
} while (needsSubdivision);
iter = next;
next = next.nextIterator();
}
PointMap.Link iterLink = iter.link;
iterLink.f = pointMap.totalLength;
control[0] = iterLink.x;
control[1] = iterLink.y;
}
private static boolean isOutOfErrorSquared(float midX, float midY,
float midPointX, float midPointY, float errorSquared) {
float xError = midPointX - midX;
float yError = midPointY - midY;
float midErrorSquared = (xError * xError) + (yError * yError);
return midErrorSquared > errorSquared;
}
private static float bezierX(float t, float[] control, boolean isCubic) {
if (isCubic) {
return cubicCoordinateCalculation(t, control[0], control[2], control[4], control[6]);
} else {
return quadraticCoordinateCalculation(t, control[0], control[2], control[4]);
}
}
private static float bezierY(float t, float[] control, boolean isCubic) {
if (isCubic) {
return cubicCoordinateCalculation(t, control[1], control[3], control[5], control[7]);
} else {
return quadraticCoordinateCalculation(t, control[1], control[3], control[5]);
}
}
private static float quadraticCoordinateCalculation(float t, float p0, float p1, float p2) {
float oneMinusT = 1 - t;
return oneMinusT * ((oneMinusT * p0) + (t * p1)) + t * ((oneMinusT * p1) + (t * p2));
}
private static float cubicCoordinateCalculation(float t, float p0, float p1, float p2, float p3) {
float oneMinusT = 1 - t;
float oneMinusTSquared = oneMinusT * oneMinusT;
float oneMinusTCubed = oneMinusTSquared * oneMinusT;
float tSquared = t * t;
float tCubed = tSquared * t;
return (oneMinusTCubed * p0) + (3 * oneMinusTSquared * t * p1)
+ (3 * oneMinusT * tSquared * p2) + (tCubed * p3);
}
private static float dist(float x1, float y1, float x2, float y2) {
final float x = (x2 - x1);
final float y = (y2 - y1);
return (float) Math.hypot(x, y);
}
}
@@ -15,10 +15,6 @@
package com.hippo.util;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -26,39 +22,6 @@ import com.hippo.widget.Hotspotable;
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;
}
}
@SuppressWarnings("RedundantCast")
public static void setHotspot(Drawable drawable, float x, float y) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@@ -1,652 +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.util;
import android.util.Log;
import com.hippo.graphics.JPath;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @hide
*/
public class JPathParser {
static final String LOGTAG = JPathParser.class.getSimpleName();
/**
* @param pathData The string representing a path, the same as "d" string in svg file.
* @return the generated Path object.
*/
public static JPath createPathFromPathData(String pathData) {
JPath path = new JPath();
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<PathDataNode> list = new ArrayList<PathDataNode>();
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 <code>source</code>.
*/
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 <code>nodesFrom</code> can morph into <code>nodesTo</code>
*/
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<PathDataNode> 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, JPath 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
* <code>nodeFrom</code> and <code>nodeTo</code> according to the
* <code>fraction</code>.
*
* @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(JPath 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(JPath 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(JPath 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;
}
}
}
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.animation;
package com.hippo.vectorold.animation;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -33,7 +33,7 @@ import android.util.Xml;
import android.view.InflateException;
import com.hippo.ehviewer.R;
import com.hippo.util.PathParser;
import com.hippo.vectorold.util.PathParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -72,12 +72,12 @@ public class AnimatorInflater {
private static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator();
/**
* Loads an {@link Animator} object from a resource
* 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 NotFoundException when the animation cannot be loaded
* @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
*/
public static Animator loadAnimator(Context context, int id)
throws NotFoundException {
@@ -208,7 +208,7 @@ public class AnimatorInflater {
/**
* Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
* Caution must be taken to ensure that the value returned from
* {@link ValueAnimator#getAnimatedValue()} is not cached, modified, or
* {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
* used across threads. The value will be modified on each <code>evaluate()</code> call.
*
* @param nodeArray The array to modify and return from <code>evaluate</code>.
@@ -313,7 +313,7 @@ public class AnimatorInflater {
* @return the PathDataEvaluator.
*/
private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim,
TypedArray arrayAnimator) {
TypedArray arrayAnimator) {
TypeEvaluator evaluator = null;
String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
@@ -371,9 +371,9 @@ public class AnimatorInflater {
throw new InflateException(arrayObjectAnimator.getPositionDescription()
+ " propertyXName or propertyYName is needed for PathData");
} else {
Path path = PathParser.createPathFromPathData(pathData);
JPath path = JPathParser.createPathFromPathData(pathData);
float error = 0.5f * pixelSize; // max half a pixel error
PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error);
PathKeyframes keyframeSet = new PathKeyframes(path, error);
Keyframes xKeyframes;
Keyframes yKeyframes;
if (getFloats) {
@@ -13,7 +13,7 @@
* limitations under the License.
*/
package com.hippo.animation;
package com.hippo.vectorold.animation;
import android.content.Context;
import android.content.res.Resources;
@@ -108,10 +108,10 @@ public class InterpolatorInflater {
} else if (name.equals("bounceInterpolator")) {
interpolator = new BounceInterpolator();
} else if (name.equals("pathInterpolator")) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
interpolator = new android.view.animation.PathInterpolator(context, attrs);
} else {
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());
@@ -13,19 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.animation;
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.graphics.JPath;
import com.hippo.util.JPathParser;
import com.hippo.vectorold.util.PathParser;
/**
* An interpolator that can traverse a Path that extends from <code>Point</code>
@@ -58,7 +59,7 @@ public class PathInterpolator implements Interpolator {
*
* @param path The <code>Path</code> to use to make the line representing the interpolator.
*/
public PathInterpolator(JPath path) {
public PathInterpolator(Path path) {
initPath(path);
}
@@ -90,7 +91,6 @@ public class PathInterpolator implements Interpolator {
this(context.getResources(), context.getTheme(), attrs);
}
/** @hide */
public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) {
TypedArray a;
if (theme != null) {
@@ -99,7 +99,6 @@ public class PathInterpolator implements Interpolator {
a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
}
parseInterpolatorFromTypeArray(a);
//setChangingConfiguration(a.getChangingConfigurations());
a.recycle();
}
@@ -108,7 +107,7 @@ public class PathInterpolator implements Interpolator {
// will be all coming from pathData.
if (a.hasValue(R.styleable.PathInterpolator_pathData)) {
String pathData = a.getString(R.styleable.PathInterpolator_pathData);
JPath path = JPathParser.createPathFromPathData(pathData);
Path path = PathParser.createPathFromPathData(pathData);
if (path == null) {
throw new InflateException("The path is null, which is created"
+ " from " + pathData);
@@ -142,49 +141,35 @@ public class PathInterpolator implements Interpolator {
}
private void initQuad(float controlX, float controlY) {
JPath path = new JPath();
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) {
JPath path = new JPath();
Path path = new Path();
path.moveTo(0, 0);
path.cubicTo(x1, y1, x2, y2, 1f, 1f);
initPath(path);
}
private void initPath(JPath path) {
float[] pointComponents = path.approximate(PRECISION);
private void initPath(Path path) {
final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */);
int numPoints = pointComponents.length / 3;
if (pointComponents[1] != 0 || pointComponents[2] != 0
|| pointComponents[pointComponents.length - 2] != 1
|| pointComponents[pointComponents.length - 1] != 1) {
throw new IllegalArgumentException("The Path must start at (0,0) and end at (1,1)");
}
final float pathLength = pathMeasure.getLength();
final int numPoints = (int) (pathLength / PRECISION) + 1;
mX = new float[numPoints];
mY = new float[numPoints];
float prevX = 0;
float prevFraction = 0;
int componentIndex = 0;
for (int i = 0; i < numPoints; i++) {
float fraction = pointComponents[componentIndex++];
float x = pointComponents[componentIndex++];
float y = pointComponents[componentIndex++];
if (fraction == prevFraction && x != prevX) {
throw new IllegalArgumentException(
"The Path cannot have discontinuity in the X axis.");
}
if (x < prevX) {
throw new IllegalArgumentException("The Path cannot loop back on itself.");
}
mX[i] = x;
mY[i] = y;
prevX = x;
prevFraction = fraction;
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];
}
}
@@ -13,7 +13,7 @@
* limitations under the License.
*/
package com.hippo.content;
package com.hippo.vectorold.content;
import android.content.Context;
import android.content.ContextWrapper;
@@ -12,7 +12,7 @@
* the License.
*/
package com.hippo.drawable;
package com.hippo.vectorold.drawable;
import android.animation.Animator;
import android.content.Context;
@@ -29,7 +29,7 @@ import android.support.v4.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import com.hippo.animation.AnimatorInflater;
import com.hippo.vectorold.animation.AnimatorInflater;
import com.hippo.ehviewer.R;
import org.xmlpull.v1.XmlPullParser;
@@ -12,7 +12,7 @@
* the License.
*/
package com.hippo.drawable;
package com.hippo.vectorold.drawable;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -38,8 +38,8 @@ import android.util.Log;
import android.util.Xml;
import com.hippo.ehviewer.R;
import com.hippo.util.DrawableUtils;
import com.hippo.util.PathParser;
import com.hippo.vectorold.util.DrawableUtils;
import com.hippo.vectorold.util.PathParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -0,0 +1,58 @@
/*
* 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
* 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;
}
}
}
@@ -12,7 +12,7 @@
* the License.
*/
package com.hippo.util;
package com.hippo.vectorold.util;
import android.graphics.Path;
import android.util.Log;