Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d2a46b7 authored by Alan Viverette's avatar Alan Viverette
Browse files

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
parent b8e046a8
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -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 {
+2 −4
Original line number Diff line number Diff line
@@ -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());
        }
+49 −33
Original line number Diff line number Diff line
@@ -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) {