feat: Add logical border radius implementation (#35572)

Summary:
This PR implements logical border-radius as requested on https://github.com/facebook/react-native/issues/34425. This implementation includes the addition of the following style properties

- `borderEndEndRadius`, equivalent to `borderBottomEndRadius`.
- `borderEndStartRadius`, equivalent to `borderBottomStartRadius`.
- `borderStartEndRadius`, equivalent to `borderTopEndRadius`.
- `borderStartStartRadius`, equivalent to `borderTopStartRadius`.

## Changelog

[GENERAL] [ADDED] - Add logical border-radius implementation

Pull Request resolved: https://github.com/facebook/react-native/pull/35572

Test Plan:
1. Open the RNTester app and navigate to the `RTLExample` page
2. Test the new style properties through the `Logical Border Radii Start/End` section

https://user-images.githubusercontent.com/11707729/206623732-6d542347-93f9-40da-be97-f7dcd5f66ca9.mov

Reviewed By: necolas

Differential Revision: D42002043

Pulled By: NickGerleman

fbshipit-source-id: a0aa9783c280398b437aeb7a00c6eb3f767657a5
This commit is contained in:
Gabriel Donadel Dall'Agnol
2023-01-06 06:00:03 -08:00
committed by Facebook GitHub Bot
parent 66927ec3aa
commit 4ae4984094
20 changed files with 234 additions and 32 deletions
@@ -139,6 +139,10 @@ public class ViewProps {
public static final String BORDER_TOP_END_RADIUS = "borderTopEndRadius";
public static final String BORDER_BOTTOM_START_RADIUS = "borderBottomStartRadius";
public static final String BORDER_BOTTOM_END_RADIUS = "borderBottomEndRadius";
public static final String BORDER_END_END_RADIUS = "borderEndEndRadius";
public static final String BORDER_END_START_RADIUS = "borderEndStartRadius";
public static final String BORDER_START_END_RADIUS = "borderStartEndRadius";
public static final String BORDER_START_START_RADIUS = "borderStartStartRadius";
public static final String BORDER_START_COLOR = "borderStartColor";
public static final String BORDER_END_COLOR = "borderEndColor";
public static final String ON_LAYOUT = "onLayout";
@@ -97,6 +97,10 @@ object ReactMapBufferPropSetter {
private const val CORNER_BOTTOM_END = 6
private const val CORNER_BOTTOM_START = 7
private const val CORNER_ALL = 8
private const val CORNER_END_END = 9
private const val CORNER_END_START = 10
private const val CORNER_START_END = 11
private const val CORNER_START_START = 12
private const val NATIVE_DRAWABLE_KIND = 0
private const val NATIVE_DRAWABLE_ATTRIBUTE = 1
@@ -365,6 +369,10 @@ object ReactMapBufferPropSetter {
CORNER_TOP_END -> 6
CORNER_BOTTOM_START -> 7
CORNER_BOTTOM_END -> 8
CORNER_END_END -> 9
CORNER_END_START -> 10
CORNER_START_END -> 11
CORNER_START_START -> 12
else -> throw IllegalArgumentException("Unknown key for border style: $key")
}
val borderRadius = entry.doubleValue
@@ -128,7 +128,11 @@ public class ReactViewBackgroundDrawable extends Drawable {
TOP_START,
TOP_END,
BOTTOM_START,
BOTTOM_END
BOTTOM_END,
END_END,
END_START,
START_END,
START_START
}
public ReactViewBackgroundDrawable(Context context) {
@@ -271,7 +275,7 @@ public class ReactViewBackgroundDrawable extends Drawable {
public void setRadius(float radius, int position) {
if (mBorderCornerRadii == null) {
mBorderCornerRadii = new float[8];
mBorderCornerRadii = new float[12];
Arrays.fill(mBorderCornerRadii, YogaConstants.UNDEFINED);
}
@@ -581,6 +585,11 @@ public class ReactViewBackgroundDrawable extends Drawable {
float bottomStartRadius = getBorderRadius(BorderRadiusLocation.BOTTOM_START);
float bottomEndRadius = getBorderRadius(BorderRadiusLocation.BOTTOM_END);
float endEndRadius = getBorderRadius(BorderRadiusLocation.END_END);
float endStartRadius = getBorderRadius(BorderRadiusLocation.END_START);
float startEndRadius = getBorderRadius(BorderRadiusLocation.START_END);
float startStartRadius = getBorderRadius(BorderRadiusLocation.START_START);
if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) {
if (YogaConstants.isUndefined(topStartRadius)) {
topStartRadius = topLeftRadius;
@@ -598,20 +607,44 @@ public class ReactViewBackgroundDrawable extends Drawable {
bottomEndRadius = bottomRightRadius;
}
final float directionAwareTopLeftRadius = isRTL ? topEndRadius : topStartRadius;
final float directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius;
final float directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius;
final float directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius;
final float logicalTopStartRadius =
YogaConstants.isUndefined(topStartRadius) ? startStartRadius : topStartRadius;
final float logicalTopEndRadius =
YogaConstants.isUndefined(topEndRadius) ? startEndRadius : topEndRadius;
final float logicalBottomStartRadius =
YogaConstants.isUndefined(bottomStartRadius) ? endStartRadius : bottomStartRadius;
final float logicalBottomEndRadius =
YogaConstants.isUndefined(bottomEndRadius) ? endEndRadius : bottomEndRadius;
final float directionAwareTopLeftRadius = isRTL ? logicalTopEndRadius : logicalTopStartRadius;
final float directionAwareTopRightRadius =
isRTL ? logicalTopStartRadius : logicalTopEndRadius;
final float directionAwareBottomLeftRadius =
isRTL ? logicalBottomEndRadius : logicalBottomStartRadius;
final float directionAwareBottomRightRadius =
isRTL ? logicalBottomStartRadius : logicalBottomEndRadius;
topLeftRadius = directionAwareTopLeftRadius;
topRightRadius = directionAwareTopRightRadius;
bottomLeftRadius = directionAwareBottomLeftRadius;
bottomRightRadius = directionAwareBottomRightRadius;
} else {
final float directionAwareTopLeftRadius = isRTL ? topEndRadius : topStartRadius;
final float directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius;
final float directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius;
final float directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius;
final float logicalTopStartRadius =
YogaConstants.isUndefined(topStartRadius) ? startStartRadius : topStartRadius;
final float logicalTopEndRadius =
YogaConstants.isUndefined(topEndRadius) ? startEndRadius : topEndRadius;
final float logicalBottomStartRadius =
YogaConstants.isUndefined(bottomStartRadius) ? endStartRadius : bottomStartRadius;
final float logicalBottomEndRadius =
YogaConstants.isUndefined(bottomEndRadius) ? endEndRadius : bottomEndRadius;
final float directionAwareTopLeftRadius = isRTL ? logicalTopEndRadius : logicalTopStartRadius;
final float directionAwareTopRightRadius =
isRTL ? logicalTopStartRadius : logicalTopEndRadius;
final float directionAwareBottomLeftRadius =
isRTL ? logicalBottomEndRadius : logicalBottomStartRadius;
final float directionAwareBottomRightRadius =
isRTL ? logicalBottomStartRadius : logicalBottomEndRadius;
if (!YogaConstants.isUndefined(directionAwareTopLeftRadius)) {
topLeftRadius = directionAwareTopLeftRadius;
@@ -119,6 +119,10 @@ public class ReactViewManager extends ReactClippingViewManager<ReactViewGroup> {
ViewProps.BORDER_TOP_END_RADIUS,
ViewProps.BORDER_BOTTOM_START_RADIUS,
ViewProps.BORDER_BOTTOM_END_RADIUS,
ViewProps.BORDER_END_END_RADIUS,
ViewProps.BORDER_END_START_RADIUS,
ViewProps.BORDER_START_END_RADIUS,
ViewProps.BORDER_START_START_RADIUS,
},
defaultFloat = YogaConstants.UNDEFINED)
public void setBorderRadius(ReactViewGroup view, int index, float borderRadius) {
@@ -113,6 +113,10 @@ constexpr MapBuffer::Key CORNER_TOP_END = 5;
constexpr MapBuffer::Key CORNER_BOTTOM_END = 6;
constexpr MapBuffer::Key CORNER_BOTTOM_START = 7;
constexpr MapBuffer::Key CORNER_ALL = 8;
constexpr MapBuffer::Key CORNER_END_END = 9;
constexpr MapBuffer::Key CORNER_END_START = 10;
constexpr MapBuffer::Key CORNER_START_END = 11;
constexpr MapBuffer::Key CORNER_START_START = 12;
inline void putOptionalFloat(
MapBufferBuilder &builder,
@@ -122,7 +126,7 @@ inline void putOptionalFloat(
}
MapBuffer convertBorderRadii(CascadedBorderRadii const &radii) {
MapBufferBuilder builder(9);
MapBufferBuilder builder(13);
putOptionalFloat(builder, CORNER_TOP_LEFT, radii.topLeft);
putOptionalFloat(builder, CORNER_TOP_RIGHT, radii.topRight);
putOptionalFloat(builder, CORNER_BOTTOM_RIGHT, radii.bottomRight);
@@ -132,6 +136,10 @@ MapBuffer convertBorderRadii(CascadedBorderRadii const &radii) {
putOptionalFloat(builder, CORNER_BOTTOM_END, radii.bottomEnd);
putOptionalFloat(builder, CORNER_BOTTOM_START, radii.bottomStart);
putOptionalFloat(builder, CORNER_ALL, radii.all);
putOptionalFloat(builder, CORNER_END_END, radii.endEnd);
putOptionalFloat(builder, CORNER_END_START, radii.endStart);
putOptionalFloat(builder, CORNER_START_END, radii.startEnd);
putOptionalFloat(builder, CORNER_START_START, radii.startStart);
return builder.build();
}