From 398512a4edd4e40b0d344406aae62a31bf8bce03 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Thu, 17 Oct 2024 17:37:25 -0700 Subject: [PATCH] Fix `getOpacity()` for drawables (#47103) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/47103 `getOpacity()` is supposed to return a PixelFormat enum instead of a value between 0..255. https://developer.android.com/reference/android/graphics/drawable/Drawable#getOpacity() Also, I'm taking the value from the paint instead of the color's alpha since the paint might've been modified by setAlpha by this point and otherwise the paint will hold the alpha set by the color anyway since setAlpha() on Paints is just a helper for setColor() (https://developer.android.com/reference/android/graphics/Paint#setAlpha(int)) Changelog: [Internal] Reviewed By: NickGerleman Differential Revision: D64273014 fbshipit-source-id: e2c524f1d816ee3705c5118232be759898e666ea --- .../uimanager/drawable/CSSBackgroundDrawable.java | 13 +++++++++++-- .../uimanager/drawable/InsetBoxShadowDrawable.kt | 9 ++++++--- .../react/uimanager/drawable/OutlineDrawable.kt | 11 +++++++++-- .../uimanager/drawable/OutsetBoxShadowDrawable.kt | 9 ++++++--- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java index 6c0f91b6c59..506b9c89304 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java @@ -18,6 +18,7 @@ import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathEffect; +import android.graphics.PixelFormat; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -189,7 +190,15 @@ public class CSSBackgroundDrawable extends Drawable { @Override public int getOpacity() { - return (Color.alpha(mColor) * mAlpha) >> 8; + int alpha = (Color.alpha(mColor) * mAlpha) >> 8; + switch (alpha) { + case 255: + return PixelFormat.OPAQUE; + case 0: + return PixelFormat.TRANSPARENT; + default: + return PixelFormat.TRANSLUCENT; + } } /* Android's elevation implementation requires this to be implemented to know where to draw the shadow. */ @@ -385,7 +394,7 @@ public class CSSBackgroundDrawable extends Drawable { canvas.clipPath(Preconditions.checkNotNull(mOuterClipPathForBorderRadius), Region.Op.INTERSECT); // Draws the View without its border first (with background color fill) - int useColor = ColorUtils.setAlphaComponent(mColor, getOpacity()); + int useColor = ColorUtils.setAlphaComponent(mColor, (Color.alpha(mColor) * mAlpha) >> 8); if (Color.alpha(useColor) != 0) { mPaint.setColor(useColor); mPaint.setStyle(Paint.Style.FILL); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt index 1910cdff8a5..a16eaa23d50 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt @@ -75,9 +75,12 @@ internal class InsetBoxShadowDrawable( @Deprecated("Deprecated in Java") override fun getOpacity(): Int { - val alpha = Color.alpha(shadowColor) - return if (alpha == 0) PixelFormat.TRANSPARENT - else ((shadowPaint.alpha / 255f) / (alpha / 255f) * 255f).roundToInt() + val alpha = shadowPaint.alpha + return when (alpha) { + 255 -> PixelFormat.OPAQUE + in 1..254 -> PixelFormat.TRANSLUCENT + else -> PixelFormat.TRANSPARENT + } } override fun draw(canvas: Canvas) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt index b8d3eeee07c..cdc0edde2d8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt @@ -15,6 +15,7 @@ import android.graphics.DashPathEffect import android.graphics.Paint import android.graphics.Path import android.graphics.PathEffect +import android.graphics.PixelFormat import android.graphics.RectF import android.graphics.drawable.Drawable import com.facebook.react.uimanager.PixelUtil.dpToPx @@ -104,8 +105,14 @@ internal class OutlineDrawable( } @Deprecated("Deprecated in Java") - override fun getOpacity(): Int = - ((outlinePaint.alpha / 255f) / (Color.alpha(outlineColor) / 255f) * 255f).roundToInt() + override fun getOpacity(): Int { + val alpha = outlinePaint.alpha + return when (alpha) { + 255 -> PixelFormat.OPAQUE + in 1..254 -> PixelFormat.TRANSLUCENT + else -> PixelFormat.TRANSPARENT + } + } override fun draw(canvas: Canvas) { if (outlineWidth == 0f) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt index 1cab38b5905..3f1f9acdb01 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt @@ -71,9 +71,12 @@ internal class OutsetBoxShadowDrawable( @Deprecated("Deprecated in Java") override fun getOpacity(): Int { - val alpha = Color.alpha(shadowColor) - return if (alpha == 0) PixelFormat.TRANSPARENT - else ((shadowPaint.alpha / 255f) / (alpha / 255f) * 255f).roundToInt() + val alpha = shadowPaint.alpha + return when (alpha) { + 255 -> PixelFormat.OPAQUE + in 1..254 -> PixelFormat.TRANSLUCENT + else -> PixelFormat.TRANSPARENT + } } override fun draw(canvas: Canvas) {