From 00c9c1ad744f60654340a02d3a71ad2117eeacf8 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 18 Oct 2017 19:30:09 -0700 Subject: [PATCH] Implement direction-aware border clipping Reviewed By: achen1 Differential Revision: D6015812 fbshipit-source-id: 406ddb12884a1c490cee784c6ef42322bd497b24 --- .../view/ReactViewBackgroundDrawable.java | 22 ++- .../react/views/view/ReactViewGroup.java | 125 +++++++++++++----- 2 files changed, 110 insertions(+), 37 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java index 394ebb97a..a638642dc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java @@ -114,7 +114,11 @@ public class ReactViewBackgroundDrawable extends Drawable { TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, - BOTTOM_LEFT + BOTTOM_LEFT, + TOP_START, + TOP_END, + BOTTOM_START, + BOTTOM_END } public ReactViewBackgroundDrawable(Context context) { @@ -262,6 +266,10 @@ public class ReactViewBackgroundDrawable extends Drawable { return YogaConstants.isUndefined(mBorderRadius) ? 0 : mBorderRadius; } + public float getBorderRadius(final BorderRadiusLocation location) { + return getBorderRadiusOrDefaultTo(YogaConstants.UNDEFINED, location); + } + public float getBorderRadiusOrDefaultTo( final float defaultValue, final BorderRadiusLocation location) { if (mBorderCornerRadii == null) { @@ -470,13 +478,13 @@ public class ReactViewBackgroundDrawable extends Drawable { float bottomRightRadius = getBorderRadiusOrDefaultTo(borderRadius, BorderRadiusLocation.BOTTOM_RIGHT); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mBorderCornerRadii != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - float topStartRadius = mBorderCornerRadii[4]; - float topEndRadius = mBorderCornerRadii[5]; - float bottomStartRadius = mBorderCornerRadii[6]; - float bottomEndRadius = mBorderCornerRadii[7]; - + float topStartRadius = getBorderRadius(BorderRadiusLocation.TOP_START); + float topEndRadius = getBorderRadius(BorderRadiusLocation.TOP_END); + float bottomStartRadius = getBorderRadius(BorderRadiusLocation.BOTTOM_START); + float bottomEndRadius = getBorderRadius(BorderRadiusLocation.BOTTOM_END); + if (I18nUtil.getInstance().doesRTLFlipLeftAndRightStyles(mContext)) { if (YogaConstants.isUndefined(topStartRadius)) { topStartRadius = topLeftRadius; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index 448c39f9a..413627e18 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -34,8 +34,8 @@ import com.facebook.react.uimanager.ReactClippingViewGroup; import com.facebook.react.uimanager.ReactClippingViewGroupHelper; import com.facebook.react.uimanager.ReactPointerEventsView; import com.facebook.react.uimanager.ReactZIndexedViewGroup; -import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper; +import com.facebook.yoga.YogaConstants; import javax.annotation.Nullable; /** @@ -644,40 +644,105 @@ public class ReactViewGroup extends ViewGroup implements float right = getWidth(); float bottom = getHeight(); - final float borderWidth = mReactBackgroundDrawable.getFullBorderWidth(); - final float borderTopWidth = - mReactBackgroundDrawable.getBorderWidthOrDefaultTo(borderWidth, Spacing.TOP); - final float borderBottomWidth = - mReactBackgroundDrawable.getBorderWidthOrDefaultTo(borderWidth, Spacing.BOTTOM); - final float borderLeftWidth = - mReactBackgroundDrawable.getBorderWidthOrDefaultTo(borderWidth, Spacing.LEFT); - final float borderRightWidth = - mReactBackgroundDrawable.getBorderWidthOrDefaultTo(borderWidth, Spacing.RIGHT); + final RectF borderWidth = mReactBackgroundDrawable.getDirectionAwareBorderInsets(); - if (borderTopWidth > 0 - || borderLeftWidth > 0 - || borderBottomWidth > 0 - || borderRightWidth > 0) { - left += borderLeftWidth; - top += borderTopWidth; - right -= borderRightWidth; - bottom -= borderBottomWidth; + if (borderWidth.top > 0 + || borderWidth.left > 0 + || borderWidth.bottom > 0 + || borderWidth.right > 0) { + left += borderWidth.left; + top += borderWidth.top; + right -= borderWidth.right; + bottom -= borderWidth.bottom; } final float borderRadius = mReactBackgroundDrawable.getFullBorderRadius(); - final float topLeftBorderRadius = + float topLeftBorderRadius = mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_LEFT); - final float topRightBorderRadius = + float topRightBorderRadius = mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_RIGHT); - final float bottomLeftBorderRadius = + float bottomLeftBorderRadius = mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_LEFT); - final float bottomRightBorderRadius = + float bottomRightBorderRadius = mReactBackgroundDrawable.getBorderRadiusOrDefaultTo( borderRadius, ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_RIGHT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final boolean isRTL = mLayoutDirection == View.LAYOUT_DIRECTION_RTL; + float topStartBorderRadius = + mReactBackgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_START); + float topEndBorderRadius = + mReactBackgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.TOP_END); + float bottomStartBorderRadius = + mReactBackgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_START); + float bottomEndBorderRadius = + mReactBackgroundDrawable.getBorderRadius( + ReactViewBackgroundDrawable.BorderRadiusLocation.BOTTOM_END); + + if (I18nUtil.getInstance().doesRTLFlipLeftAndRightStyles(getContext())) { + if (YogaConstants.isUndefined(topStartBorderRadius)) { + topStartBorderRadius = topLeftBorderRadius; + } + + if (YogaConstants.isUndefined(topEndBorderRadius)) { + topEndBorderRadius = topRightBorderRadius; + } + + if (YogaConstants.isUndefined(bottomStartBorderRadius)) { + bottomStartBorderRadius = bottomLeftBorderRadius; + } + + if (YogaConstants.isUndefined(bottomEndBorderRadius)) { + bottomEndBorderRadius = bottomRightBorderRadius; + } + + final float directionAwareTopLeftRadius = + isRTL ? topEndBorderRadius : topStartBorderRadius; + final float directionAwareTopRightRadius = + isRTL ? topStartBorderRadius : topEndBorderRadius; + final float directionAwareBottomLeftRadius = + isRTL ? bottomEndBorderRadius : bottomStartBorderRadius; + final float directionAwareBottomRightRadius = + isRTL ? bottomStartBorderRadius : bottomEndBorderRadius; + + topLeftBorderRadius = directionAwareTopLeftRadius; + topRightBorderRadius = directionAwareTopRightRadius; + bottomLeftBorderRadius = directionAwareBottomLeftRadius; + bottomRightBorderRadius = directionAwareBottomRightRadius; + } else { + final float directionAwareTopLeftRadius = + isRTL ? topEndBorderRadius : topStartBorderRadius; + final float directionAwareTopRightRadius = + isRTL ? topStartBorderRadius : topEndBorderRadius; + final float directionAwareBottomLeftRadius = + isRTL ? bottomEndBorderRadius : bottomStartBorderRadius; + final float directionAwareBottomRightRadius = + isRTL ? bottomStartBorderRadius : bottomEndBorderRadius; + + if (!YogaConstants.isUndefined(directionAwareTopLeftRadius)) { + topLeftBorderRadius = directionAwareTopLeftRadius; + } + + if (!YogaConstants.isUndefined(directionAwareTopRightRadius)) { + topRightBorderRadius = directionAwareTopRightRadius; + } + + if (!YogaConstants.isUndefined(directionAwareBottomLeftRadius)) { + bottomLeftBorderRadius = directionAwareBottomLeftRadius; + } + + if (!YogaConstants.isUndefined(directionAwareBottomRightRadius)) { + bottomRightBorderRadius = directionAwareBottomRightRadius; + } + } + } + if (topLeftBorderRadius > 0 || topRightBorderRadius > 0 || bottomRightBorderRadius > 0 @@ -690,14 +755,14 @@ public class ReactViewGroup extends ViewGroup implements mPath.addRoundRect( new RectF(left, top, right, bottom), new float[] { - Math.max(topLeftBorderRadius - borderLeftWidth, 0), - Math.max(topLeftBorderRadius - borderTopWidth, 0), - Math.max(topRightBorderRadius - borderRightWidth, 0), - Math.max(topRightBorderRadius - borderTopWidth, 0), - Math.max(bottomRightBorderRadius - borderRightWidth, 0), - Math.max(bottomRightBorderRadius - borderBottomWidth, 0), - Math.max(bottomLeftBorderRadius - borderLeftWidth, 0), - Math.max(bottomLeftBorderRadius - borderBottomWidth, 0), + Math.max(topLeftBorderRadius - borderWidth.left, 0), + Math.max(topLeftBorderRadius - borderWidth.top, 0), + Math.max(topRightBorderRadius - borderWidth.right, 0), + Math.max(topRightBorderRadius - borderWidth.top, 0), + Math.max(bottomRightBorderRadius - borderWidth.right, 0), + Math.max(bottomRightBorderRadius - borderWidth.bottom, 0), + Math.max(bottomLeftBorderRadius - borderWidth.left, 0), + Math.max(bottomLeftBorderRadius - borderWidth.bottom, 0), }, Path.Direction.CW); canvas.clipPath(mPath);