diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9eb6f7426595d..0b72c2cb6c75a 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4780,6 +4780,18 @@ + + + + + + + + + + + + @@ -4788,12 +4800,6 @@ - - - - - - diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 492376fea7258..b85e85ce3c01f 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -39,7 +39,6 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; /** @@ -289,6 +288,7 @@ public class VectorDrawable extends Drawable { noViewportTag = false; } else if (SHAPE_GROUP.equals(tagName)) { currentGroup = new VGroup(); + currentGroup.inflate(res, attrs, theme); pathRenderer.mGroupList.add(currentGroup); noGroupTag = false; } @@ -325,8 +325,6 @@ public class VectorDrawable extends Drawable { throw new XmlPullParserException("no " + tag + " defined"); } - // post parse cleanup - pathRenderer.parseFinish(); return pathRenderer; } @@ -373,7 +371,6 @@ public class VectorDrawable extends Drawable { private final Path mRenderPath = new Path(); private final Matrix mMatrix = new Matrix(); - private VPath[] mCurrentPaths; private Paint mStrokePaint; private Paint mFillPaint; private ColorFilter mColorFilter; @@ -391,12 +388,6 @@ public class VectorDrawable extends Drawable { public VPathRenderer(VPathRenderer copy) { mGroupList.addAll(copy.mGroupList); - if (copy.mCurrentPaths != null) { - mCurrentPaths = new VPath[copy.mCurrentPaths.length]; - for (int i = 0; i < mCurrentPaths.length; i++) { - mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]); - } - } mBaseWidth = copy.mBaseWidth; mBaseHeight = copy.mBaseHeight; @@ -422,7 +413,9 @@ public class VectorDrawable extends Drawable { public void applyTheme(Theme t) { final ArrayList groups = mGroupList; for (int i = groups.size() - 1; i >= 0; i--) { - final ArrayList paths = groups.get(i).mVGList; + VGroup currentGroup = groups.get(i); + currentGroup.applyTheme(t); + final ArrayList paths = currentGroup.mVGList; for (int j = paths.size() - 1; j >= 0; j--) { final VPath path = paths.get(j); if (path.canApplyTheme()) { @@ -446,104 +439,98 @@ public class VectorDrawable extends Drawable { } public void draw(Canvas canvas, int w, int h) { - if (mCurrentPaths == null) { - Log.e(LOGTAG,"mCurrentPaths == null"); + if (mGroupList == null || mGroupList.size() == 0) { + Log.e(LOGTAG,"There is no group to draw"); return; } - for (int i = 0; i < mCurrentPaths.length; i++) { - if (mCurrentPaths[i] != null) { - drawPath(mCurrentPaths[i], canvas, w, h); + for (int i = 0; i < mGroupList.size(); i++) { + VGroup currentGroup = mGroupList.get(i); + if (currentGroup != null) { + drawPath(currentGroup, canvas, w, h); } } } - private void drawPath(VPath vPath, Canvas canvas, int w, int h) { + private void drawPath(VGroup vGroup, Canvas canvas, int w, int h) { final float scale = Math.min(h / mViewportHeight, w / mViewportWidth); - vPath.toPath(mPath); - final Path path = mPath; - - if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { - float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; - float end = (vPath.mTrimPathEnd + vPath.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.reset(); mMatrix.reset(); - mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY); + mMatrix.postRotate(vGroup.mRotate, vGroup.mPivotX, vGroup.mPivotY); mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f); mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f); - mRenderPath.addPath(path, mMatrix); + ArrayList paths = vGroup.getPaths(); + for (int i = 0; i < paths.size(); i++) { + VPath vPath = paths.get(i); + vPath.toPath(mPath); + final Path path = mPath; - if (vPath.mClip) { - canvas.clipPath(mRenderPath, Region.Op.REPLACE); - } + if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { + float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; + float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f; - if (vPath.mFillColor != 0) { - if (mFillPaint == null) { - mFillPaint = new Paint(); - mFillPaint.setColorFilter(mColorFilter); - mFillPaint.setStyle(Paint.Style.FILL); - mFillPaint.setAntiAlias(true); + 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 } - mFillPaint.setColor(vPath.mFillColor); - canvas.drawPath(mRenderPath, mFillPaint); - } + mRenderPath.reset(); - if (vPath.mStrokeColor != 0) { - if (mStrokePaint == null) { - mStrokePaint = new Paint(); - mStrokePaint.setColorFilter(mColorFilter); - mStrokePaint.setStyle(Paint.Style.STROKE); - mStrokePaint.setAntiAlias(true); + mRenderPath.addPath(path, mMatrix); + + if (vPath.mClip) { + canvas.clipPath(mRenderPath, Region.Op.REPLACE); } - final Paint strokePaint = mStrokePaint; - if (vPath.mStrokeLineJoin != null) { - strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); + if (vPath.mFillColor != 0) { + if (mFillPaint == null) { + mFillPaint = new Paint(); + mFillPaint.setColorFilter(mColorFilter); + mFillPaint.setStyle(Paint.Style.FILL); + mFillPaint.setAntiAlias(true); + } + + mFillPaint.setColor(vPath.mFillColor); + canvas.drawPath(mRenderPath, mFillPaint); } - if (vPath.mStrokeLineCap != null) { - strokePaint.setStrokeCap(vPath.mStrokeLineCap); + if (vPath.mStrokeColor != 0) { + if (mStrokePaint == null) { + mStrokePaint = new Paint(); + mStrokePaint.setColorFilter(mColorFilter); + mStrokePaint.setStyle(Paint.Style.STROKE); + mStrokePaint.setAntiAlias(true); + } + + final Paint strokePaint = mStrokePaint; + if (vPath.mStrokeLineJoin != null) { + strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); + } + + if (vPath.mStrokeLineCap != null) { + strokePaint.setStrokeCap(vPath.mStrokeLineCap); + } + + strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); + strokePaint.setColor(vPath.mStrokeColor); + strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); + canvas.drawPath(mRenderPath, strokePaint); } - - strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); - strokePaint.setColor(vPath.mStrokeColor); - strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); - canvas.drawPath(mRenderPath, strokePaint); - } - } - - /** - * Build the "current" path based on the current group - * TODO: improve memory use & performance or move to C++ - */ - public void parseFinish() { - final Collection paths = mGroupList.get(0).getPaths(); - mCurrentPaths = paths.toArray(new VPath[paths.size()]); - for (int i = 0; i < mCurrentPaths.length; i++) { - mCurrentPaths[i] = new VPath(mCurrentPaths[i]); } } @@ -587,17 +574,60 @@ public class VectorDrawable extends Drawable { private final HashMap mVGPathMap = new HashMap(); private final ArrayList mVGList = new ArrayList(); + private float mRotate = 0; + private float mPivotX = 0; + private float mPivotY = 0; + + private int[] mThemeAttrs; + public void add(VPath path) { String id = path.getID(); mVGPathMap.put(id, path); mVGList.add(path); } + public void applyTheme(Theme t) { + if (mThemeAttrs == null) { + return; + } + + final TypedArray a = t.resolveAttributes( + mThemeAttrs, R.styleable.VectorDrawablePath); + + mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); + mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); + mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); + a.recycle(); + } + + public void inflate(Resources res, AttributeSet attrs, Theme theme) { + final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup); + final int[] themeAttrs = a.extractThemeAttrs(); + + mThemeAttrs = themeAttrs; + // NOTE: The set of attributes loaded here MUST match the + // set of attributes loaded in applyTheme. + + if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) { + mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate); + } + + if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) { + mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX); + } + + if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) { + mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY); + } + + a.recycle(); + } + /** * Must return in order of adding * @return ordered list of paths */ - public Collection getPaths() { + public ArrayList getPaths() { return mVGList; } @@ -616,10 +646,6 @@ public class VectorDrawable extends Drawable { int mFillRule; float mFillOpacity = Float.NaN; - float mRotate = 0; - float mPivotX = 0; - float mPivotY = 0; - float mTrimPathStart = 0; float mTrimPathEnd = 1; float mTrimPathOffset = 0; @@ -631,18 +657,11 @@ public class VectorDrawable extends Drawable { private VNode[] mNode = null; private String mId; - private int[] mCheckState = new int[MAX_STATES]; - private boolean[] mCheckValue = new boolean[MAX_STATES]; - private int mNumberOfStates = 0; public VPath() { // Empty constructor. } - public VPath(VPath p) { - copyFrom(p); - } - public void toPath(Path path) { path.reset(); if (mNode != null) { @@ -707,18 +726,6 @@ public class VectorDrawable extends Drawable { mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); } - if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) { - mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate); - } - - if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) { - mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX); - } - - if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) { - mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY); - } - if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) { mStrokeLineCap = getStrokeLineCap( @@ -797,10 +804,6 @@ public class VectorDrawable extends Drawable { mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor); mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity); - mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate); - mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX); - mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY); - mStrokeLineCap = getStrokeLineCap(a.getInt( R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap); mStrokeLineJoin = getStrokeLineJoin(a.getInt( @@ -819,6 +822,7 @@ public class VectorDrawable extends Drawable { R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart); updateColorAlphas(); + a.recycle(); } private void updateColorAlphas() { @@ -921,33 +925,6 @@ public class VectorDrawable extends Drawable { } return list.toArray(new VectorDrawable.VNode[list.size()]); } - - public void copyFrom(VPath p1) { - mNode = new VNode[p1.mNode.length]; - for (int i = 0; i < mNode.length; i++) { - mNode[i] = new VNode(p1.mNode[i]); - } - mId = p1.mId; - mStrokeColor = p1.mStrokeColor; - mFillColor = p1.mFillColor; - mStrokeWidth = p1.mStrokeWidth; - mRotate = p1.mRotate; - mPivotX = p1.mPivotX; - mPivotY = p1.mPivotY; - mTrimPathStart = p1.mTrimPathStart; - mTrimPathEnd = p1.mTrimPathEnd; - mTrimPathOffset = p1.mTrimPathOffset; - mStrokeLineCap = p1.mStrokeLineCap; - mStrokeLineJoin = p1.mStrokeLineJoin; - mStrokeMiterlimit = p1.mStrokeMiterlimit; - mNumberOfStates = p1.mNumberOfStates; - for (int i = 0; i < mNumberOfStates; i++) { - mCheckState[i] = p1.mCheckState[i]; - mCheckValue[i] = p1.mCheckValue[i]; - } - - mFillRule = p1.mFillRule; - } } private static class VNode { diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml index db5697c232533..40f23f0c4bc1a 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml @@ -15,21 +15,22 @@ + android:width="64dp" + android:height="64dp"/> - - + + diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml index 8e8250d9ee21a..5b4c4abe3aa67 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml @@ -1,4 +1,5 @@ -