diff options
Diffstat (limited to 'src/com/android/bitmap/drawable')
-rw-r--r-- | src/com/android/bitmap/drawable/CircularBitmapDrawable.java | 15 | ||||
-rw-r--r-- | src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java | 143 |
2 files changed, 146 insertions, 12 deletions
diff --git a/src/com/android/bitmap/drawable/CircularBitmapDrawable.java b/src/com/android/bitmap/drawable/CircularBitmapDrawable.java index 8536f58..a4af368 100644 --- a/src/com/android/bitmap/drawable/CircularBitmapDrawable.java +++ b/src/com/android/bitmap/drawable/CircularBitmapDrawable.java @@ -43,6 +43,7 @@ public class CircularBitmapDrawable extends ExtendedBitmapDrawable { private final Paint mBorderPaint = new Paint(); private float mBorderWidth; + private Bitmap mShaderBitmap; public CircularBitmapDrawable(Resources res, BitmapCache cache, boolean limitDensity) { @@ -120,20 +121,22 @@ public class CircularBitmapDrawable extends ExtendedBitmapDrawable { protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, final Rect src, final Rect dst, final float alpha) { // Draw bitmap through shader first. - BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP, - TileMode.CLAMP); - sMatrix.reset(); + BitmapShader shader = (BitmapShader) mBitmapPaint.getShader(); + if (shader == null || mShaderBitmap != bitmap) { + shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP); + mShaderBitmap = bitmap; + mBitmapPaint.setShader(shader); + } + sMatrix.reset(); // Fit bitmap to bounds. float scale = Math.max((float) dst.width() / src.width(), (float) dst.height() / src.height()); sMatrix.postScale(scale, scale); - // Translate bitmap to dst bounds. sMatrix.postTranslate(dst.left, dst.top); - shader.setLocalMatrix(sMatrix); - mBitmapPaint.setShader(shader); + int oldAlpha = mBitmapPaint.getAlpha(); mBitmapPaint.setAlpha((int) (oldAlpha * alpha)); canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2, diff --git a/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java b/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java index d5d04b3..e23642d 100644 --- a/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java +++ b/src/com/android/bitmap/drawable/StyledCornersBitmapDrawable.java @@ -53,7 +53,9 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { private final Paint mFlapPaint = new Paint(); private final Paint mBorderPaint = new Paint(); + private final Paint mCompatibilityModeBackgroundPaint = new Paint(); private final Path mClipPath = new Path(); + private final Path mCompatibilityModePath = new Path(); private final float mCornerRoundRadius; private final float mCornerFlapSide; @@ -63,6 +65,7 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { private int mBottomLeftCornerStyle = CORNER_STYLE_SHARP; private int mScrimColor; private float mBorderWidth; + private boolean mIsCompatibilityMode; /** * Create a new StyledCornersBitmapDrawable. @@ -77,12 +80,17 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { mFlapPaint.setColor(Color.TRANSPARENT); mFlapPaint.setStyle(Style.FILL); + mFlapPaint.setAntiAlias(true); mBorderPaint.setColor(Color.TRANSPARENT); mBorderPaint.setStyle(Style.STROKE); mBorderPaint.setStrokeWidth(mBorderWidth); mBorderPaint.setAntiAlias(true); + mCompatibilityModeBackgroundPaint.setColor(Color.TRANSPARENT); + mCompatibilityModeBackgroundPaint.setStyle(Style.FILL); + mCompatibilityModeBackgroundPaint.setAntiAlias(true); + mScrimColor = Color.TRANSPARENT; } @@ -129,6 +137,13 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { } /** + * Get the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}. + */ + public int getFlapColor() { + return mFlapPaint.getColor(); + } + + /** * Set the flap color for all corners that have style {@link #CORNER_STYLE_SHARP}. * * Use {@link android.graphics.Color#TRANSPARENT} to disable flap colors. @@ -163,6 +178,34 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { } } + /** + * Sets whether we should work around an issue introduced in Android 4.4.3, + * where a WebView can corrupt the stencil buffer of the canvas when the canvas is clipped + * using a non-rectangular Path. + */ + public void setCompatibilityMode(boolean isCompatibilityMode) { + boolean changed = mIsCompatibilityMode != isCompatibilityMode; + mIsCompatibilityMode = isCompatibilityMode; + + if (changed) { + invalidateSelf(); + } + } + + /** + * Sets the color of the container that this drawable is in. The given color will be used in + * {@link #setCompatibilityMode compatibility mode} to draw fake corners to emulate clipped + * corners. + */ + public void setCompatibilityModeBackgroundColor(int color) { + boolean changed = mCompatibilityModeBackgroundPaint.getColor() != color; + mCompatibilityModeBackgroundPaint.setColor(color); + + if (changed) { + invalidateSelf(); + } + } + @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); @@ -182,8 +225,10 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { } // Clip to path. - canvas.save(); - canvas.clipPath(mClipPath); + if (!mIsCompatibilityMode) { + canvas.save(); + canvas.clipPath(mClipPath); + } // Draw parent within path. super.draw(canvas); @@ -191,7 +236,7 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { // Draw scrim on top of parent. canvas.drawColor(mScrimColor); - // Draw flap. + // Draw flaps. float left = bounds.left + mBorderWidth / 2; float top = bounds.top + mBorderWidth / 2; float right = bounds.right - mBorderWidth / 2; @@ -221,14 +266,100 @@ public class StyledCornersBitmapDrawable extends ExtendedBitmapDrawable { mCornerRoundRadius, mFlapPaint); } - canvas.restore(); + if (!mIsCompatibilityMode) { + canvas.restore(); + } + + if (mIsCompatibilityMode) { + drawFakeCornersForCompatibilityMode(canvas); + } // Draw border around path. canvas.drawPath(mClipPath, mBorderPaint); } - protected Path getClipPath() { - return mClipPath; + protected void drawFakeCornersForCompatibilityMode(final Canvas canvas) { + final Rect bounds = getBounds(); + + float left = bounds.left; + float top = bounds.top; + float right = bounds.right; + float bottom = bounds.bottom; + + // Draw fake round corners. + RectF fakeCornerRectF = sRectF; + fakeCornerRectF.set(0, 0, mCornerRoundRadius * 2, mCornerRoundRadius * 2); + if (mTopLeftCornerStyle == CORNER_STYLE_ROUND) { + fakeCornerRectF.offsetTo(left, top); + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(left, top); + mCompatibilityModePath.lineTo(left + mCornerRoundRadius, top); + mCompatibilityModePath.arcTo(fakeCornerRectF, START_TOP, -QUARTER_CIRCLE); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + if (mTopRightCornerStyle == CORNER_STYLE_ROUND) { + fakeCornerRectF.offsetTo(right - fakeCornerRectF.width(), top); + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(right, top); + mCompatibilityModePath.lineTo(right, top + mCornerRoundRadius); + mCompatibilityModePath.arcTo(fakeCornerRectF, START_RIGHT, -QUARTER_CIRCLE); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + if (mBottomRightCornerStyle == CORNER_STYLE_ROUND) { + fakeCornerRectF + .offsetTo(right - fakeCornerRectF.width(), bottom - fakeCornerRectF.height()); + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(right, bottom); + mCompatibilityModePath.lineTo(right - mCornerRoundRadius, bottom); + mCompatibilityModePath.arcTo(fakeCornerRectF, START_BOTTOM, -QUARTER_CIRCLE); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + if (mBottomLeftCornerStyle == CORNER_STYLE_ROUND) { + fakeCornerRectF.offsetTo(left, bottom - fakeCornerRectF.height()); + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(left, bottom); + mCompatibilityModePath.lineTo(left, bottom - mCornerRoundRadius); + mCompatibilityModePath.arcTo(fakeCornerRectF, START_LEFT, -QUARTER_CIRCLE); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + + // Draw fake flap corners. + if (mTopLeftCornerStyle == CORNER_STYLE_FLAP) { + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(left, top); + mCompatibilityModePath.lineTo(left + mCornerFlapSide, top); + mCompatibilityModePath.lineTo(left, top + mCornerFlapSide); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + if (mTopRightCornerStyle == CORNER_STYLE_FLAP) { + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(right, top); + mCompatibilityModePath.lineTo(right, top + mCornerFlapSide); + mCompatibilityModePath.lineTo(right - mCornerFlapSide, top); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + if (mBottomRightCornerStyle == CORNER_STYLE_FLAP) { + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(right, bottom); + mCompatibilityModePath.lineTo(right - mCornerFlapSide, bottom); + mCompatibilityModePath.lineTo(right, bottom - mCornerFlapSide); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } + if (mBottomLeftCornerStyle == CORNER_STYLE_FLAP) { + mCompatibilityModePath.rewind(); + mCompatibilityModePath.moveTo(left, bottom); + mCompatibilityModePath.lineTo(left, bottom - mCornerFlapSide); + mCompatibilityModePath.lineTo(left + mCornerFlapSide, bottom); + mCompatibilityModePath.close(); + canvas.drawPath(mCompatibilityModePath, mCompatibilityModeBackgroundPaint); + } } private void recalculatePath() { |