From c49e3ce6c6ac5100dc5a73c6bd12cbfda4d4ca76 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Mon, 18 Aug 2014 18:15:36 -0700 Subject: Don't cast shadows from gradients with transparent parts bug:17070982 Change-Id: I607dd3c9397845fce53b7f097ec0b57246077ea1 --- graphics/java/android/graphics/Outline.java | 38 +++++++++++++--------- .../graphics/drawable/GradientDrawable.java | 32 +++++++++--------- 2 files changed, 38 insertions(+), 32 deletions(-) (limited to 'graphics/java/android') diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java index 3177023edda7..4bf0b71b6fc2 100644 --- a/graphics/java/android/graphics/Outline.java +++ b/graphics/java/android/graphics/Outline.java @@ -18,15 +18,15 @@ package android.graphics; import android.annotation.NonNull; import android.graphics.drawable.Drawable; -import android.view.View; /** * Defines a simple shape, used for bounding graphical regions. *

- * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a - * View, or to clip the contents of the View. + * Can be computed for a View, or computed by a Drawable, to drive the shape of + * shadows cast by a View, or to clip the contents of the View. * - * @see View#setOutline(Outline) + * @see android.view.ViewOutlineProvider + * @see android.view.View#setOutlineProvider(android.view.ViewOutlineProvider) * @see Drawable#getOutline(Outline) */ public final class Outline { @@ -79,21 +79,27 @@ public final class Outline { /** * Returns whether the outline can be used to clip a View. + *

+ * Currently, only Outlines that can be represented as a rectangle, circle, + * or round rect support clipping. * - * Currently, only outlines that can be represented as a rectangle, circle, or round rect - * support clipping. - * - * @see {@link View#setClipToOutline(boolean)} + * @see {@link android.view.View#setClipToOutline(boolean)} */ public boolean canClip() { return !isEmpty() && mRect != null; } /** - * Sets the alpha represented by the Outline. - * - * Content producing a fully opaque (alpha = 1.0f) outline is assumed by the drawing system - * to fully cover content beneath it, meaning content beneath may be optimized away. + * Sets the alpha represented by the Outline - the degree to which the + * producer is guaranteed to be opaque over the Outline's shape. + *

+ * An alpha value of 0.0f either represents completely + * transparent content, or content that isn't guaranteed to fill the shape + * it publishes. + *

+ * Content producing a fully opaque (alpha = 1.0f) outline is + * assumed by the drawing system to fully cover content beneath it, + * meaning content beneath may be optimized away. */ public void setAlpha(float alpha) { mAlpha = alpha; @@ -130,7 +136,8 @@ public final class Outline { } /** - * Sets the Outline to the rounded rect defined by the input rect, and corner radius. + * Sets the Outline to the rounded rect defined by the input rect, and + * corner radius. */ public void setRect(int left, int top, int right, int bottom) { setRoundRect(left, top, right, bottom, 0.0f); @@ -145,7 +152,7 @@ public final class Outline { /** * Sets the Outline to the rounded rect defined by the input rect, and corner radius. - * + *

* Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)} */ public void setRoundRect(int left, int top, int right, int bottom, float radius) { @@ -196,7 +203,8 @@ public final class Outline { } /** - * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}. + * Sets the Constructs an Outline from a + * {@link android.graphics.Path#isConvex() convex path}. */ public void setConvexPath(@NonNull Path convexPath) { if (convexPath.isEmpty()) { diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index a383aabd5a80..29b914153461 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -820,7 +820,7 @@ public class GradientDrawable extends Drawable { @Override public int getOpacity() { - return (mAlpha == 255 && mGradientState.mOpaque) ? + return (mAlpha == 255 && mGradientState.mOpaqueOverBounds) ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; } @@ -1413,7 +1413,8 @@ public class GradientDrawable extends Drawable { public void getOutline(Outline outline) { final GradientState st = mGradientState; final Rect bounds = getBounds(); - outline.setAlpha(mAlpha / 255.0f); + // only report non-zero alpha if shape being drawn is opaque + outline.setAlpha(st.mOpaqueOverShape ? (mAlpha / 255.0f) : 0.0f); switch (st.mShape) { case RECTANGLE: @@ -1492,7 +1493,8 @@ public class GradientDrawable extends Drawable { private int mGradientRadiusType = RADIUS_TYPE_PIXELS; private boolean mUseLevel; private boolean mUseLevelForShape; - private boolean mOpaque; + private boolean mOpaqueOverBounds; + private boolean mOpaqueOverShape; int[] mThemeAttrs; int[] mAttrSize; @@ -1544,7 +1546,7 @@ public class GradientDrawable extends Drawable { mGradientRadiusType = state.mGradientRadiusType; mUseLevel = state.mUseLevel; mUseLevelForShape = state.mUseLevelForShape; - mOpaque = state.mOpaque; + mOpaqueOverBounds = state.mOpaqueOverBounds; mThemeAttrs = state.mThemeAttrs; mAttrSize = state.mAttrSize; mAttrGradient = state.mAttrGradient; @@ -1606,40 +1608,36 @@ public class GradientDrawable extends Drawable { } private void computeOpacity() { - if (mShape != RECTANGLE) { - mOpaque = false; - return; - } - - if (mRadius > 0 || mRadiusArray != null) { - mOpaque = false; - return; - } + mOpaqueOverBounds = false; + mOpaqueOverShape = false; + // First test opacity of all colors if (mStrokeWidth > 0) { if (mStrokeColorStateList != null) { if (!mStrokeColorStateList.isOpaque()) { - mOpaque = false; return; } } } if (mColorStateList != null && !mColorStateList.isOpaque()) { - mOpaque = false; return; } if (mColors != null) { for (int i = 0; i < mColors.length; i++) { if (!isOpaque(mColors[i])) { - mOpaque = false; return; } } } - mOpaque = true; + // Colors are opaque, so opaqueOverShape=true, + mOpaqueOverShape = true; + // and opaqueOverBounds=true if shape fills bounds + mOpaqueOverBounds = mShape == RECTANGLE + && mRadius <= 0 + && mRadiusArray == null; } private static boolean isOpaque(int color) { -- cgit v1.2.3-59-g8ed1b