Scale bitmap shaders for target density
Also fixes progress bar sample tile to reflect density and ensures that ProgressBar.tileify() clones inner drawables into the correct density. Bug: 31841123 Test: BitmapDrawableTest#testPreloadDensity() Test: ThemeHostTest Test: Visual inspection of ApiDemos Change-Id: I9dcb9817d8d91d61ff0215987247e9e7fb089c46
This commit is contained in:
@ -22,6 +22,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@ -230,7 +231,7 @@ public class ProgressBar extends View {
|
||||
private Drawable mCurrentDrawable;
|
||||
private ProgressTintInfo mProgressTintInfo;
|
||||
|
||||
Bitmap mSampleTile;
|
||||
int mSampleWidth = 0;
|
||||
private boolean mNoInvalidate;
|
||||
private Interpolator mInterpolator;
|
||||
private RefreshProgressRunnable mRefreshProgressRunnable;
|
||||
@ -505,15 +506,14 @@ public class ProgressBar extends View {
|
||||
}
|
||||
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
final BitmapDrawable bitmap = (BitmapDrawable) drawable;
|
||||
final Bitmap tileBitmap = bitmap.getBitmap();
|
||||
if (mSampleTile == null) {
|
||||
mSampleTile = tileBitmap;
|
||||
}
|
||||
|
||||
final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
|
||||
final Drawable.ConstantState cs = drawable.getConstantState();
|
||||
final BitmapDrawable clone = (BitmapDrawable) cs.newDrawable(getResources());
|
||||
clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
|
||||
|
||||
if (mSampleWidth <= 0) {
|
||||
mSampleWidth = clone.getIntrinsicWidth();
|
||||
}
|
||||
|
||||
if (clip) {
|
||||
return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
|
||||
} else {
|
||||
|
@ -281,10 +281,8 @@ public class RatingBar extends AbsSeekBar {
|
||||
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (mSampleTile != null) {
|
||||
// TODO: Once ProgressBar's TODOs are gone, this can be done more
|
||||
// cleanly than mSampleTile
|
||||
final int width = mSampleTile.getWidth() * mNumStars;
|
||||
if (mSampleWidth > 0) {
|
||||
final int width = mSampleWidth * mNumStars;
|
||||
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
|
||||
getMeasuredHeight());
|
||||
}
|
||||
|
@ -463,31 +463,14 @@ public class BitmapDrawable extends Drawable {
|
||||
return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
|
||||
}
|
||||
|
||||
private void updateMirrorMatrix(float dx) {
|
||||
if (mMirrorMatrix == null) {
|
||||
mMirrorMatrix = new Matrix();
|
||||
}
|
||||
mMirrorMatrix.setTranslate(dx, 0);
|
||||
mMirrorMatrix.preScale(-1.0f, 1.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
mDstRectAndInsetsDirty = true;
|
||||
|
||||
final Bitmap bitmap = mBitmapState.mBitmap;
|
||||
final Shader shader = mBitmapState.mPaint.getShader();
|
||||
if (shader != null) {
|
||||
if (needMirroring()) {
|
||||
updateMirrorMatrix(bounds.right - bounds.left);
|
||||
shader.setLocalMatrix(mMirrorMatrix);
|
||||
mBitmapState.mPaint.setShader(shader);
|
||||
} else {
|
||||
if (mMirrorMatrix != null) {
|
||||
mMirrorMatrix = null;
|
||||
shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
|
||||
mBitmapState.mPaint.setShader(shader);
|
||||
}
|
||||
}
|
||||
if (bitmap != null && shader != null) {
|
||||
updateShaderMatrix(bitmap, mBitmapState.mPaint, shader, needMirroring());
|
||||
}
|
||||
}
|
||||
|
||||
@ -548,19 +531,7 @@ public class BitmapDrawable extends Drawable {
|
||||
canvas.restore();
|
||||
}
|
||||
} else {
|
||||
if (needMirroring) {
|
||||
// Mirror the bitmap
|
||||
updateMirrorMatrix(mDstRect.right - mDstRect.left);
|
||||
shader.setLocalMatrix(mMirrorMatrix);
|
||||
paint.setShader(shader);
|
||||
} else {
|
||||
if (mMirrorMatrix != null) {
|
||||
mMirrorMatrix = null;
|
||||
shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
|
||||
paint.setShader(shader);
|
||||
}
|
||||
}
|
||||
|
||||
updateShaderMatrix(bitmap, paint, shader, needMirroring);
|
||||
canvas.drawRect(mDstRect, paint);
|
||||
}
|
||||
|
||||
@ -573,6 +544,51 @@ public class BitmapDrawable extends Drawable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@code paint}'s shader matrix to be consistent with the
|
||||
* destination size and layout direction.
|
||||
*
|
||||
* @param bitmap the bitmap to be drawn
|
||||
* @param paint the paint used to draw the bitmap
|
||||
* @param shader the shader to set on the paint
|
||||
* @param needMirroring whether the bitmap should be mirrored
|
||||
*/
|
||||
private void updateShaderMatrix(@NonNull Bitmap bitmap, @NonNull Paint paint,
|
||||
@NonNull Shader shader, boolean needMirroring) {
|
||||
final int sourceDensity = bitmap.getDensity();
|
||||
final int targetDensity = mTargetDensity;
|
||||
final boolean needScaling = sourceDensity != 0 && sourceDensity != targetDensity;
|
||||
if (needScaling || needMirroring) {
|
||||
final Matrix matrix = getOrCreateMirrorMatrix();
|
||||
matrix.reset();
|
||||
|
||||
if (needMirroring) {
|
||||
final int dx = mDstRect.right - mDstRect.left;
|
||||
matrix.setTranslate(dx, 0);
|
||||
matrix.setScale(-1, 1);
|
||||
}
|
||||
|
||||
if (needScaling) {
|
||||
final float densityScale = targetDensity / (float) sourceDensity;
|
||||
matrix.postScale(densityScale, densityScale);
|
||||
}
|
||||
|
||||
shader.setLocalMatrix(matrix);
|
||||
} else {
|
||||
mMirrorMatrix = null;
|
||||
shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
|
||||
}
|
||||
|
||||
paint.setShader(shader);
|
||||
}
|
||||
|
||||
private Matrix getOrCreateMirrorMatrix() {
|
||||
if (mMirrorMatrix == null) {
|
||||
mMirrorMatrix = new Matrix();
|
||||
}
|
||||
return mMirrorMatrix;
|
||||
}
|
||||
|
||||
private void updateDstRectAndInsetsIfDirty() {
|
||||
if (mDstRectAndInsetsDirty) {
|
||||
if (mBitmapState.mTileModeX == null && mBitmapState.mTileModeY == null) {
|
||||
|
Reference in New Issue
Block a user