Skip to content

Commit

Permalink
Add support for assymetrical bonder radii when using % (#45985)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #45985

As title.

We can now create ellipses when using percentages. The algorithm for this is still flawed and to get it to be a 1:1 to web it will probably require a re-write of some of the logic but this should get us closer for now.

Some examples:

1. Border thinning on large single corner radii (100%)
 {F1798145800}
2. Thinning gets worse when having irregular border colors (100%)
 {F1798148002}

Changelog: [Internal]

Differential Revision: D61025927
  • Loading branch information
jorge-cab authored and facebook-github-bot committed Aug 12, 2024
1 parent d01f1b3 commit 7850926
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 113 deletions.
41 changes: 28 additions & 13 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -4360,7 +4360,7 @@ public final class com/facebook/react/uimanager/LengthPercentage {
public fun <init> ()V
public fun <init> (FLcom/facebook/react/uimanager/LengthPercentageType;)V
public final fun getUnit ()Lcom/facebook/react/uimanager/LengthPercentageType;
public final fun resolve (FF)F
public final fun resolve (FF)Lcom/facebook/react/uimanager/style/CornerRadii;
public static final fun setFromDynamic (Lcom/facebook/react/bridge/Dynamic;)Lcom/facebook/react/uimanager/LengthPercentage;
}

Expand Down Expand Up @@ -6113,19 +6113,19 @@ public final class com/facebook/react/uimanager/style/BoxShadow$Companion {

public final class com/facebook/react/uimanager/style/ComputedBorderRadius {
public fun <init> ()V
public fun <init> (FFFF)V
public final fun component1 ()F
public final fun component2 ()F
public final fun component3 ()F
public final fun component4 ()F
public final fun copy (FFFF)Lcom/facebook/react/uimanager/style/ComputedBorderRadius;
public static synthetic fun copy$default (Lcom/facebook/react/uimanager/style/ComputedBorderRadius;FFFFILjava/lang/Object;)Lcom/facebook/react/uimanager/style/ComputedBorderRadius;
public fun <init> (Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;)V
public final fun component1 ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun component2 ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun component3 ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun component4 ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun copy (Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;)Lcom/facebook/react/uimanager/style/ComputedBorderRadius;
public static synthetic fun copy$default (Lcom/facebook/react/uimanager/style/ComputedBorderRadius;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;Lcom/facebook/react/uimanager/style/CornerRadii;ILjava/lang/Object;)Lcom/facebook/react/uimanager/style/ComputedBorderRadius;
public fun equals (Ljava/lang/Object;)Z
public final fun get (Lcom/facebook/react/uimanager/style/ComputedBorderRadiusProp;)F
public final fun getBottomLeft ()F
public final fun getBottomRight ()F
public final fun getTopLeft ()F
public final fun getTopRight ()F
public final fun get (Lcom/facebook/react/uimanager/style/ComputedBorderRadiusProp;)Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun getBottomLeft ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun getBottomRight ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun getTopLeft ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun getTopRight ()Lcom/facebook/react/uimanager/style/CornerRadii;
public final fun hasRoundedBorders ()Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand All @@ -6141,6 +6141,21 @@ public final class com/facebook/react/uimanager/style/ComputedBorderRadiusProp :
public static fun values ()[Lcom/facebook/react/uimanager/style/ComputedBorderRadiusProp;
}

public final class com/facebook/react/uimanager/style/CornerRadii {
public fun <init> ()V
public fun <init> (FF)V
public synthetic fun <init> (FFILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()F
public final fun component2 ()F
public final fun copy (FF)Lcom/facebook/react/uimanager/style/CornerRadii;
public static synthetic fun copy$default (Lcom/facebook/react/uimanager/style/CornerRadii;FFILjava/lang/Object;)Lcom/facebook/react/uimanager/style/CornerRadii;
public fun equals (Ljava/lang/Object;)Z
public final fun getHorizontal ()F
public final fun getVertical ()F
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/facebook/react/uimanager/style/Gradient {
public fun <init> (Lcom/facebook/react/bridge/ReadableMap;)V
public final fun getShader (Landroid/graphics/Rect;)Landroid/graphics/Shader;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.facebook.common.logging.FLog
import com.facebook.react.bridge.Dynamic
import com.facebook.react.bridge.ReadableType
import com.facebook.react.common.ReactConstants
import com.facebook.react.uimanager.style.CornerRadii
import java.lang.NumberFormatException

public enum class LengthPercentageType {
Expand Down Expand Up @@ -61,12 +62,12 @@ public class LengthPercentage(
}
}

public fun resolve(width: Float, height: Float): Float {
public fun resolve(width: Float, height: Float): CornerRadii {
if (unit == LengthPercentageType.PERCENT) {
return (value / 100) * Math.min(width, height)
return CornerRadii((value / 100) * width, (value / 100) * height)
}

return value
return CornerRadii(value, value)
}

public constructor() : this(0f, LengthPercentageType.POINT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.facebook.react.uimanager.style.BorderRadiusStyle;
import com.facebook.react.uimanager.style.BorderStyle;
import com.facebook.react.uimanager.style.ComputedBorderRadius;
import com.facebook.react.uimanager.style.CornerRadii;
import com.facebook.react.uimanager.style.Gradient;
import java.util.Locale;
import java.util.Objects;
Expand Down Expand Up @@ -662,21 +663,27 @@ private void updatePath() {
mContext,
mOuterClipTempRectForBorderRadius.width(),
mOuterClipTempRectForBorderRadius.height());
float topLeftRadius = mComputedBorderRadius.getTopLeft();
float topRightRadius = mComputedBorderRadius.getTopRight();
float bottomLeftRadius = mComputedBorderRadius.getBottomLeft();
float bottomRightRadius = mComputedBorderRadius.getBottomRight();

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);
CornerRadii topLeftRadius = mComputedBorderRadius.getTopLeft();
CornerRadii topRightRadius = mComputedBorderRadius.getTopRight();
CornerRadii bottomLeftRadius = mComputedBorderRadius.getBottomLeft();
CornerRadii bottomRightRadius = mComputedBorderRadius.getBottomRight();

final float innerTopLeftRadiusX =
getInnerBorderRadius(topLeftRadius.getHorizontal(), borderWidth.left);
final float innerTopLeftRadiusY =
getInnerBorderRadius(topLeftRadius.getVertical(), borderWidth.top);
final float innerTopRightRadiusX =
getInnerBorderRadius(topRightRadius.getHorizontal(), borderWidth.right);
final float innerTopRightRadiusY =
getInnerBorderRadius(topRightRadius.getVertical(), borderWidth.top);
final float innerBottomRightRadiusX =
getInnerBorderRadius(bottomRightRadius, borderWidth.right);
getInnerBorderRadius(bottomRightRadius.getHorizontal(), borderWidth.right);
final float innerBottomRightRadiusY =
getInnerBorderRadius(bottomRightRadius, borderWidth.bottom);
final float innerBottomLeftRadiusX = getInnerBorderRadius(bottomLeftRadius, borderWidth.left);
final float innerBottomLeftRadiusY = getInnerBorderRadius(bottomLeftRadius, borderWidth.bottom);
getInnerBorderRadius(bottomRightRadius.getVertical(), borderWidth.bottom);
final float innerBottomLeftRadiusX =
getInnerBorderRadius(bottomLeftRadius.getHorizontal(), borderWidth.left);
final float innerBottomLeftRadiusY =
getInnerBorderRadius(bottomLeftRadius.getVertical(), borderWidth.bottom);

mInnerClipPathForBorderRadius.addRoundRect(
mInnerClipTempRectForBorderRadius,
Expand Down Expand Up @@ -716,14 +723,14 @@ private void updatePath() {
mOuterClipPathForBorderRadius.addRoundRect(
mOuterClipTempRectForBorderRadius,
new float[] {
topLeftRadius,
topLeftRadius,
topRightRadius,
topRightRadius,
bottomRightRadius,
bottomRightRadius,
bottomLeftRadius,
bottomLeftRadius
topLeftRadius.getHorizontal(),
topLeftRadius.getVertical(),
topRightRadius.getHorizontal(),
topRightRadius.getVertical(),
bottomRightRadius.getHorizontal(),
bottomRightRadius.getVertical(),
bottomLeftRadius.getHorizontal(),
bottomLeftRadius.getVertical()
},
Path.Direction.CW);

Expand All @@ -736,44 +743,56 @@ private void updatePath() {
mPathForBorderRadiusOutline.addRoundRect(
mTempRectForBorderRadiusOutline,
new float[] {
topLeftRadius + extraRadiusForOutline,
topLeftRadius + extraRadiusForOutline,
topRightRadius + extraRadiusForOutline,
topRightRadius + extraRadiusForOutline,
bottomRightRadius + extraRadiusForOutline,
bottomRightRadius + extraRadiusForOutline,
bottomLeftRadius + extraRadiusForOutline,
bottomLeftRadius + extraRadiusForOutline
topLeftRadius.getHorizontal() + extraRadiusForOutline,
topLeftRadius.getVertical() + extraRadiusForOutline,
topRightRadius.getHorizontal() + extraRadiusForOutline,
topRightRadius.getVertical() + extraRadiusForOutline,
bottomRightRadius.getHorizontal() + extraRadiusForOutline,
bottomRightRadius.getVertical() + extraRadiusForOutline,
bottomLeftRadius.getHorizontal() + extraRadiusForOutline,
bottomLeftRadius.getVertical() + extraRadiusForOutline
},
Path.Direction.CW);

mCenterDrawPath.addRoundRect(
mTempRectForCenterDrawPath,
new float[] {
Math.max(
topLeftRadius - borderWidth.left * 0.5f,
(borderWidth.left > 0.0f) ? (topLeftRadius / borderWidth.left) : 0.0f),
topLeftRadius.getHorizontal() - borderWidth.left * 0.5f,
(borderWidth.left > 0.0f)
? (topLeftRadius.getHorizontal() / borderWidth.left)
: 0.0f),
Math.max(
topLeftRadius - borderWidth.top * 0.5f,
(borderWidth.top > 0.0f) ? (topLeftRadius / borderWidth.top) : 0.0f),
topLeftRadius.getVertical() - borderWidth.top * 0.5f,
(borderWidth.top > 0.0f) ? (topLeftRadius.getVertical() / borderWidth.top) : 0.0f),
Math.max(
topRightRadius - borderWidth.right * 0.5f,
(borderWidth.right > 0.0f) ? (topRightRadius / borderWidth.right) : 0.0f),
topRightRadius.getHorizontal() - borderWidth.right * 0.5f,
(borderWidth.right > 0.0f)
? (topRightRadius.getHorizontal() / borderWidth.right)
: 0.0f),
Math.max(
topRightRadius - borderWidth.top * 0.5f,
(borderWidth.top > 0.0f) ? (topRightRadius / borderWidth.top) : 0.0f),
topRightRadius.getVertical() - borderWidth.top * 0.5f,
(borderWidth.top > 0.0f) ? (topRightRadius.getVertical() / borderWidth.top) : 0.0f),
Math.max(
bottomRightRadius - borderWidth.right * 0.5f,
(borderWidth.right > 0.0f) ? (bottomRightRadius / borderWidth.right) : 0.0f),
bottomRightRadius.getHorizontal() - borderWidth.right * 0.5f,
(borderWidth.right > 0.0f)
? (bottomRightRadius.getHorizontal() / borderWidth.right)
: 0.0f),
Math.max(
bottomRightRadius - borderWidth.bottom * 0.5f,
(borderWidth.bottom > 0.0f) ? (bottomRightRadius / borderWidth.bottom) : 0.0f),
bottomRightRadius.getVertical() - borderWidth.bottom * 0.5f,
(borderWidth.bottom > 0.0f)
? (bottomRightRadius.getVertical() / borderWidth.bottom)
: 0.0f),
Math.max(
bottomLeftRadius - borderWidth.left * 0.5f,
(borderWidth.left > 0.0f) ? (bottomLeftRadius / borderWidth.left) : 0.0f),
bottomLeftRadius.getHorizontal() - borderWidth.left * 0.5f,
(borderWidth.left > 0.0f)
? (bottomLeftRadius.getHorizontal() / borderWidth.left)
: 0.0f),
Math.max(
bottomLeftRadius - borderWidth.bottom * 0.5f,
(borderWidth.bottom > 0.0f) ? (bottomLeftRadius / borderWidth.bottom) : 0.0f)
bottomLeftRadius.getVertical() - borderWidth.bottom * 0.5f,
(borderWidth.bottom > 0.0f)
? (bottomLeftRadius.getVertical() / borderWidth.bottom)
: 0.0f)
},
Path.Direction.CW);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,14 @@ internal class InsetBoxShadowDrawable(
val bottomLeftRadius = computedBorderRadii.bottomLeft
val bottomRightRadius = computedBorderRadii.bottomRight

val innerTopLeftRadius = background.getInnerBorderRadius(topLeftRadius, borderWidth.left)
val innerTopRightRadius = background.getInnerBorderRadius(topRightRadius, borderWidth.right)
val innerTopLeftRadius =
background.getInnerBorderRadius(topLeftRadius.horizontal, borderWidth.left)
val innerTopRightRadius =
background.getInnerBorderRadius(topRightRadius.horizontal, borderWidth.right)
val innerBottomRightRadius =
background.getInnerBorderRadius(bottomRightRadius, borderWidth.right)
val innerBottomLeftRadius = background.getInnerBorderRadius(bottomLeftRadius, borderWidth.left)
background.getInnerBorderRadius(bottomRightRadius.horizontal, borderWidth.right)
val innerBottomLeftRadius =
background.getInnerBorderRadius(bottomLeftRadius.horizontal, borderWidth.left)

val spreadWithDirection = -spread.toFloat()
return BorderRadiusStyle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.facebook.react.uimanager.FilterHelper
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.style.BorderRadiusStyle
import com.facebook.react.uimanager.style.ComputedBorderRadius
import com.facebook.react.uimanager.style.CornerRadii
import kotlin.math.roundToInt

private const val TAG = "OutsetBoxShadowDrawable"
Expand Down Expand Up @@ -91,10 +92,22 @@ internal class OutsetBoxShadowDrawable(
val shadowBorderRadii =
computedBorderRadii?.let { radii ->
ComputedBorderRadius(
topLeft = adjustRadiusForSpread(radii.topLeft, spreadExtent.toFloat()),
topRight = adjustRadiusForSpread(radii.topRight, spreadExtent.toFloat()),
bottomRight = adjustRadiusForSpread(radii.bottomRight, spreadExtent.toFloat()),
bottomLeft = adjustRadiusForSpread(radii.bottomLeft, spreadExtent.toFloat()),
topLeft =
CornerRadii(
adjustRadiusForSpread(radii.topLeft.horizontal, spreadExtent.toFloat()),
adjustRadiusForSpread(radii.topLeft.vertical, spreadExtent.toFloat())),
topRight =
CornerRadii(
adjustRadiusForSpread(radii.topRight.horizontal, spreadExtent.toFloat()),
adjustRadiusForSpread(radii.topRight.vertical, spreadExtent.toFloat())),
bottomRight =
CornerRadii(
adjustRadiusForSpread(radii.bottomRight.horizontal, spreadExtent.toFloat()),
adjustRadiusForSpread(radii.bottomRight.vertical, spreadExtent.toFloat())),
bottomLeft =
CornerRadii(
adjustRadiusForSpread(radii.bottomLeft.horizontal, spreadExtent.toFloat()),
adjustRadiusForSpread(radii.bottomLeft.vertical, spreadExtent.toFloat())),
)
}

Expand All @@ -105,7 +118,6 @@ internal class OutsetBoxShadowDrawable(
lastBorderRadius = shadowBorderRadii
shadowOuterRect.set(
RectF(bounds).apply { inset(-spreadExtent.toFloat(), -spreadExtent.toFloat()) })

// We remove the portion of the shadow which overlaps the background border box, to avoid
// showing the shadow shape e.g. behind a transparent background. There may be a subpixel gap
// between the border box path, and the edge of border rendering, so we slightly inflate the
Expand All @@ -118,28 +130,28 @@ internal class OutsetBoxShadowDrawable(
shadowClipOutPath.addRoundRect(
subpixelInsetBounds,
floatArrayOf(
computedBorderRadii.topLeft,
computedBorderRadii.topLeft,
computedBorderRadii.topRight,
computedBorderRadii.topRight,
computedBorderRadii.bottomRight,
computedBorderRadii.bottomRight,
computedBorderRadii.bottomLeft,
computedBorderRadii.bottomLeft),
computedBorderRadii.topLeft.horizontal,
computedBorderRadii.topLeft.vertical,
computedBorderRadii.topRight.horizontal,
computedBorderRadii.topRight.vertical,
computedBorderRadii.bottomRight.horizontal,
computedBorderRadii.bottomRight.vertical,
computedBorderRadii.bottomLeft.horizontal,
computedBorderRadii.bottomLeft.vertical),
Path.Direction.CW)

shadowOuterPath.rewind()
shadowOuterPath.addRoundRect(
shadowOuterRect,
floatArrayOf(
shadowBorderRadii.topLeft,
shadowBorderRadii.topLeft,
shadowBorderRadii.topRight,
shadowBorderRadii.topRight,
shadowBorderRadii.bottomRight,
shadowBorderRadii.bottomRight,
shadowBorderRadii.bottomLeft,
shadowBorderRadii.bottomLeft),
shadowBorderRadii.topLeft.horizontal,
shadowBorderRadii.topLeft.vertical,
shadowBorderRadii.topRight.horizontal,
shadowBorderRadii.topRight.vertical,
shadowBorderRadii.bottomRight.horizontal,
shadowBorderRadii.bottomRight.vertical,
shadowBorderRadii.bottomLeft.horizontal,
shadowBorderRadii.bottomLeft.vertical),
Path.Direction.CW)
}

Expand Down
Loading

0 comments on commit 7850926

Please sign in to comment.