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

Commit c49e3ce6 authored by Chris Craik's avatar Chris Craik
Browse files

Don't cast shadows from gradients with transparent parts

bug:17070982
Change-Id: I607dd3c9397845fce53b7f097ec0b57246077ea1
parent 49e057d7
Loading
Loading
Loading
Loading
+23 −15
Original line number Diff line number Diff line
@@ -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.
 * <p>
 * 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.
     * <p>
     * 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.
     * <p>
     * An alpha value of <code>0.0f</code> either represents completely
     * transparent content, or content that isn't guaranteed to fill the shape
     * it publishes.
     * <p>
     * Content producing a fully opaque (alpha = <code>1.0f</code>) 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.
     *
     * <p>
     * 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()) {
+15 −17
Original line number Diff line number Diff line
@@ -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) {