Implement direction-aware border clipping

Reviewed By: achen1

Differential Revision: D6015812

fbshipit-source-id: 406ddb12884a1c490cee784c6ef42322bd497b24
This commit is contained in:
Ramanpreet Nara 2017-10-18 19:30:09 -07:00 committed by Facebook Github Bot
parent 875f273dba
commit 00c9c1ad74
2 changed files with 110 additions and 37 deletions

View File

@ -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;

View File

@ -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);