summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorztenghui <ztenghui@google.com>2015-01-13 16:21:11 -0800
committerztenghui <ztenghui@google.com>2015-07-17 11:16:41 -0700
commit35289f12d6cb0f0db67489876c805ad4a3cbd5f6 (patch)
tree4f8c82b14b54af261462ca8e7ed79dbc2b8417aa
parentd4b566bf56333de708908ce4accb5fb067be64f0 (diff)
downloadframeworks_base-35289f12d6cb0f0db67489876c805ad4a3cbd5f6.zip
frameworks_base-35289f12d6cb0f0db67489876c805ad4a3cbd5f6.tar.gz
frameworks_base-35289f12d6cb0f0db67489876c805ad4a3cbd5f6.tar.bz2
Scaling (Animated)VectorDrawable inside ImageView
Before, the VectorDrawable is behaving like BitmapDrawable inside a ImageView, and it can be blurry due to scaling. Now apply the scaling information to the cached bitmap, then the size of bitmap will match the ImageView's screen size. Therefore, no blurry any more. b/18185626 Change-Id: I979cef3b5178a9bd37ee6cc776df3361ca47c803
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java83
-rw-r--r--tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java15
2 files changed, 65 insertions, 33 deletions
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 24cb055..1cfccc4 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -200,6 +200,11 @@ public class VectorDrawable extends Drawable {
private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2;
+ // Cap the bitmap size, such that it won't hurt the performance too much
+ // and it won't crash due to a very large scale.
+ // The drawable will look blurry above this size.
+ private static final int MAX_CACHED_BITMAP_SIZE = 2048;
+
private static final boolean DBG_VECTOR_DRAWABLE = false;
private VectorDrawableState mVectorState;
@@ -219,6 +224,11 @@ public class VectorDrawable extends Drawable {
private int mDpiScaledHeight = 0;
private Insets mDpiScaleInsets = Insets.NONE;
+ // Temp variable, only for saving "new" operation at the draw() time.
+ private final float[] mTmpFloats = new float[9];
+ private final Matrix mTmpMatrix = new Matrix();
+ private final Rect mTmpBounds = new Rect();
+
public VectorDrawable() {
this(null, null);
}
@@ -262,44 +272,59 @@ public class VectorDrawable extends Drawable {
@Override
public void draw(Canvas canvas) {
- final Rect bounds = getBounds();
- if (bounds.width() <= 0 || bounds.height() <= 0) {
+ // We will offset the bounds for drawBitmap, so copyBounds() here instead
+ // of getBounds().
+ copyBounds(mTmpBounds);
+ if (mTmpBounds.width() <= 0 || mTmpBounds.height() <= 0) {
// Nothing to draw
return;
}
+ // Color filters always override tint filters.
+ final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
+
+ // The imageView can scale the canvas in different ways, in order to
+ // avoid blurry scaling, we have to draw into a bitmap with exact pixel
+ // size first. This bitmap size is determined by the bounds and the
+ // canvas scale.
+ canvas.getMatrix(mTmpMatrix);
+ mTmpMatrix.getValues(mTmpFloats);
+ float canvasScaleX = Math.abs(mTmpFloats[Matrix.MSCALE_X]);
+ float canvasScaleY = Math.abs(mTmpFloats[Matrix.MSCALE_Y]);
+ int scaledWidth = (int) (mTmpBounds.width() * canvasScaleX);
+ int scaledHeight = (int) (mTmpBounds.height() * canvasScaleY);
+ scaledWidth = Math.min(MAX_CACHED_BITMAP_SIZE, scaledWidth);
+ scaledHeight = Math.min(MAX_CACHED_BITMAP_SIZE, scaledHeight);
+
+ if (scaledWidth <= 0 || scaledHeight <= 0) {
+ return;
+ }
+
final int saveCount = canvas.save();
- final boolean needMirroring = needMirroring();
+ canvas.translate(mTmpBounds.left, mTmpBounds.top);
- canvas.translate(bounds.left, bounds.top);
+ // Handle RTL mirroring.
+ final boolean needMirroring = needMirroring();
if (needMirroring) {
- canvas.translate(bounds.width(), 0);
+ canvas.translate(mTmpBounds.width(), 0);
canvas.scale(-1.0f, 1.0f);
}
- // Color filters always override tint filters.
- final ColorFilter colorFilter = mColorFilter == null ? mTintFilter : mColorFilter;
+ // At this point, canvas has been translated to the right position.
+ // And we use this bound for the destination rect for the drawBitmap, so
+ // we offset to (0, 0);
+ mTmpBounds.offsetTo(0, 0);
+ mVectorState.createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
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);
- }
+ mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
} else {
- // Static Vector Drawable case.
- mVectorState.createCachedBitmapIfNeeded(bounds);
if (!mVectorState.canReuseCache()) {
- mVectorState.updateCachedBitmap(bounds);
+ mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
mVectorState.updateCacheStates();
}
- mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
}
-
+ mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter, mTmpBounds);
canvas.restoreToCount(saveCount);
}
@@ -770,10 +795,11 @@ public class VectorDrawable extends Drawable {
}
}
- public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter) {
+ public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter,
+ Rect originalBounds) {
// The bitmap's size is the same as the bounds.
final Paint p = getPaint(filter);
- canvas.drawBitmap(mCachedBitmap, 0, 0, p);
+ canvas.drawBitmap(mCachedBitmap, null, originalBounds, p);
}
public boolean hasTranslucentRoot() {
@@ -797,16 +823,15 @@ public class VectorDrawable extends Drawable {
return mTempPaint;
}
- public void updateCachedBitmap(Rect bounds) {
+ public void updateCachedBitmap(int width, int height) {
mCachedBitmap.eraseColor(Color.TRANSPARENT);
Canvas tmpCanvas = new Canvas(mCachedBitmap);
- mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height(), null);
+ mVPathRenderer.draw(tmpCanvas, width, height, null);
}
- public void createCachedBitmapIfNeeded(Rect bounds) {
- if (mCachedBitmap == null || !canReuseBitmap(bounds.width(),
- bounds.height())) {
- mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
+ public void createCachedBitmapIfNeeded(int width, int height) {
+ if (mCachedBitmap == null || !canReuseBitmap(width, height)) {
+ mCachedBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
mCacheDirty = true;
}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java
index 3787843..c5be6c4 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java
@@ -37,8 +37,8 @@ public class ScaleDrawableTests extends Activity {
};
protected int icon = R.drawable.bitmap_drawable01;
-
protected int vector_icon = R.drawable.vector_drawable16;
+ protected int animated_vector_icon = R.drawable.ic_hourglass_animation;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -46,12 +46,12 @@ public class ScaleDrawableTests extends Activity {
ScrollView scrollView = new ScrollView(this);
GridLayout container = new GridLayout(this);
scrollView.addView(container);
- container.setColumnCount(3);
+ container.setColumnCount(4);
container.setBackgroundColor(0xFF888888);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- params.width = 400;
- params.height = 300;
+ params.width = 300;
+ params.height = 200;
for (int i = 0; i < scaleTypes.length; i++) {
TextView t = new TextView(this);
@@ -71,6 +71,13 @@ public class ScaleDrawableTests extends Activity {
view.setScaleType(scaleType);
view.setImageResource(vector_icon);
container.addView(view);
+
+ ImageView avd_view = new ImageView(this);
+ avd_view.setLayoutParams(params);
+ avd_view.setScaleType(scaleType);
+ avd_view.setImageResource(animated_vector_icon);
+ container.addView(avd_view);
+
}
setContentView(scrollView);