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 7369bc9de442db..90e501ba112508 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 @@ -309,6 +309,12 @@ public BorderRadiusStyle getBorderRadius() { return mBorderRadius; } + // Here, "inner" refers to the border radius on the inside of the border. So + // it ends up being the "outer" border radius inset by the respective width. + public float getInnerBorderRadius(float computedRadius, float borderWidth) { + return Math.max(computedRadius - borderWidth, 0); + } + public ComputedBorderRadius getComputedBorderRadius() { return mComputedBorderRadius; } @@ -640,14 +646,16 @@ private void updatePath() { float bottomLeftRadius = mComputedBorderRadius.getBottomLeft(); float bottomRightRadius = mComputedBorderRadius.getBottomRight(); - final float innerTopLeftRadiusX = Math.max(topLeftRadius - borderWidth.left, 0); - final float innerTopLeftRadiusY = Math.max(topLeftRadius - borderWidth.top, 0); - final float innerTopRightRadiusX = Math.max(topRightRadius - borderWidth.right, 0); - final float innerTopRightRadiusY = Math.max(topRightRadius - borderWidth.top, 0); - final float innerBottomRightRadiusX = Math.max(bottomRightRadius - borderWidth.right, 0); - final float innerBottomRightRadiusY = Math.max(bottomRightRadius - borderWidth.bottom, 0); - final float innerBottomLeftRadiusX = Math.max(bottomLeftRadius - borderWidth.left, 0); - final float innerBottomLeftRadiusY = Math.max(bottomLeftRadius - borderWidth.bottom, 0); + final float innerTopLeftRadiusX = getInnerBorderRadius(topLeftRadius, borderWidth.left); + final float innerTopLeftRadiusY = getInnerBorderRadius(topLeftRadius, borderWidth.top); + final float innerTopRightRadiusX = getInnerBorderRadius(topRightRadius, borderWidth.right); + final float innerTopRightRadiusY = getInnerBorderRadius(topRightRadius, borderWidth.top); + final float innerBottomRightRadiusX = + getInnerBorderRadius(bottomRightRadius, borderWidth.right); + final float innerBottomRightRadiusY = + getInnerBorderRadius(bottomRightRadius, borderWidth.bottom); + final float innerBottomLeftRadiusX = getInnerBorderRadius(bottomLeftRadius, borderWidth.left); + final float innerBottomLeftRadiusY = getInnerBorderRadius(bottomLeftRadius, borderWidth.bottom); mInnerClipPathForBorderRadius.addRoundRect( mInnerClipTempRectForBorderRadius, 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 6197c920cec382..e4de5d921fe77d 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 @@ -18,7 +18,11 @@ import androidx.annotation.RequiresApi import com.facebook.common.logging.FLog import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.uimanager.FilterHelper +import com.facebook.react.uimanager.LengthPercentage +import com.facebook.react.uimanager.LengthPercentageType import com.facebook.react.uimanager.PixelUtil +import com.facebook.react.uimanager.style.BorderRadiusProp +import com.facebook.react.uimanager.style.BorderRadiusStyle import kotlin.math.roundToInt private const val TAG = "InsetBoxShadowDrawable" @@ -76,13 +80,10 @@ internal class InsetBoxShadowDrawable( clearRegionBounds.inset(spreadExtent, spreadExtent) clearRegionBounds.offset( PixelUtil.toPixelFromDIP(offsetX).roundToInt() + padding / 2, - PixelUtil.toPixelFromDIP(offsetY).roundToInt() + padding / 2) + PixelUtil.toPixelFromDIP(offsetY).roundToInt() + padding / 2, + ) val clearRegionBorderRadii = - getShadowBorderRadii( - -spreadExtent.toFloat(), - background.borderRadius, - clearRegionBounds.width().toFloat(), - clearRegionBounds.height().toFloat()) + getClearRegionBorderRadii(spreadExtent, background, clearRegionBounds) if (shadowPaint.colorFilter != colorFilter || clearRegionDrawable.layoutDirection != layoutDirection || @@ -129,4 +130,49 @@ internal class InsetBoxShadowDrawable( canvas.restore() } } + + private fun getClearRegionBorderRadii( + spread: Int, + background: CSSBackgroundDrawable, + clearRegionBounds: Rect, + ): BorderRadiusStyle { + val computedBorderRadii = background.computedBorderRadius + val borderWidth = background.getDirectionAwareBorderInsets() + + val topLeftRadius = computedBorderRadii.topLeft + val topRightRadius = computedBorderRadii.topRight + val bottomLeftRadius = computedBorderRadii.bottomLeft + val bottomRightRadius = computedBorderRadii.bottomRight + + val innerTopLeftRadius = background.getInnerBorderRadius(topLeftRadius, borderWidth.left) + val innerTopRightRadius = background.getInnerBorderRadius(topRightRadius, borderWidth.right) + val innerBottomRightRadius = + background.getInnerBorderRadius(bottomRightRadius, borderWidth.right) + val innerBottomLeftRadius = background.getInnerBorderRadius(bottomLeftRadius, borderWidth.left) + + val innerBorderRadii = BorderRadiusStyle() + innerBorderRadii.set( + BorderRadiusProp.BORDER_TOP_LEFT_RADIUS, + LengthPercentage(innerTopLeftRadius, LengthPercentageType.POINT), + ) + innerBorderRadii.set( + BorderRadiusProp.BORDER_TOP_RIGHT_RADIUS, + LengthPercentage(innerTopRightRadius, LengthPercentageType.POINT), + ) + innerBorderRadii.set( + BorderRadiusProp.BORDER_BOTTOM_RIGHT_RADIUS, + LengthPercentage(innerBottomRightRadius, LengthPercentageType.POINT), + ) + innerBorderRadii.set( + BorderRadiusProp.BORDER_BOTTOM_LEFT_RADIUS, + LengthPercentage(innerBottomLeftRadius, LengthPercentageType.POINT), + ) + + return getShadowBorderRadii( + -spread.toFloat(), + innerBorderRadii, + clearRegionBounds.width().toFloat(), + clearRegionBounds.height().toFloat(), + ) + } }