mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Revert D57668976: Simplify ReactViewGroup clip to border
Differential Revision: D57668976 Original commit changeset: 8b8cf956dc86 Original Phabricator Diff: D57668976 fbshipit-source-id: 5147557c1f3561863b1ad9226ca6244ff94cb29c
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ac51deeaf4
commit
91d12d9b99
@@ -5557,21 +5557,21 @@ public abstract interface class com/facebook/react/uimanager/debug/NotThreadSafe
|
||||
|
||||
public class com/facebook/react/uimanager/drawable/CSSBackgroundDrawable : android/graphics/drawable/Drawable {
|
||||
public fun <init> (Landroid/content/Context;)V
|
||||
public fun borderBoxPath ()Landroid/graphics/Path;
|
||||
public fun draw (Landroid/graphics/Canvas;)V
|
||||
public fun getAlpha ()I
|
||||
public fun getBorderBoxPath ()Landroid/graphics/Path;
|
||||
public fun getBorderColor (I)I
|
||||
public fun getBorderRadius ()Lcom/facebook/react/uimanager/style/BorderRadiusStyle;
|
||||
public fun getBorderWidthOrDefaultTo (FI)F
|
||||
public fun getComputedBorderRadius ()Lcom/facebook/react/uimanager/style/ComputedBorderRadius;
|
||||
public fun getDirectionAwareBorderInsets ()Landroid/graphics/RectF;
|
||||
public fun getFullBorderWidth ()F
|
||||
public fun getLayoutDirection ()I
|
||||
public fun getOpacity ()I
|
||||
public fun getOutline (Landroid/graphics/Outline;)V
|
||||
public fun getPaddingBoxPath ()Landroid/graphics/Path;
|
||||
public fun getPaddingBoxRect ()Landroid/graphics/RectF;
|
||||
public fun hasRoundedBorders ()Z
|
||||
protected fun onBoundsChange (Landroid/graphics/Rect;)V
|
||||
public fun paddingBoxPath ()Landroid/graphics/Path;
|
||||
public fun setAlpha (I)V
|
||||
public fun setBorderColor (IFF)V
|
||||
public fun setBorderRadius (Lcom/facebook/react/uimanager/style/BorderRadiusProp;Lcom/facebook/react/uimanager/LengthPercentage;)V
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ internal class BoxShadowDrawable(
|
||||
}
|
||||
|
||||
with(canvas) {
|
||||
clipOutPath(background.getBorderBoxPath())
|
||||
clipOutPath(background.borderBoxPath())
|
||||
drawRenderNode(renderNode)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-18
@@ -316,35 +316,22 @@ public class CSSBackgroundDrawable extends Drawable {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
public Path getBorderBoxPath() {
|
||||
public Path borderBoxPath() {
|
||||
updatePath();
|
||||
return Preconditions.checkNotNull(mOuterClipPathForBorderRadius);
|
||||
}
|
||||
|
||||
public Path getPaddingBoxPath() {
|
||||
public Path paddingBoxPath() {
|
||||
updatePath();
|
||||
return Preconditions.checkNotNull(mInnerClipPathForBorderRadius);
|
||||
}
|
||||
|
||||
public RectF getPaddingBoxRect() {
|
||||
RectF insets = getDirectionAwareBorderInsets();
|
||||
if (insets == null) {
|
||||
return new RectF(0, 0, getBounds().width(), getBounds().height());
|
||||
}
|
||||
|
||||
return new RectF(
|
||||
insets.left,
|
||||
insets.top,
|
||||
getBounds().width() - insets.right,
|
||||
getBounds().height() - insets.bottom);
|
||||
}
|
||||
|
||||
private void drawRoundedBackgroundWithBorders(Canvas canvas) {
|
||||
updatePath();
|
||||
canvas.save();
|
||||
|
||||
// Clip outer border
|
||||
canvas.clipPath(getBorderBoxPath(), Region.Op.INTERSECT);
|
||||
canvas.clipPath(borderBoxPath(), Region.Op.INTERSECT);
|
||||
|
||||
// Draws the View without its border first (with background color fill)
|
||||
int useColor = ColorUtils.setAlphaComponent(mColor, getOpacity());
|
||||
@@ -403,7 +390,7 @@ public class CSSBackgroundDrawable extends Drawable {
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
// Clip inner border
|
||||
canvas.clipPath(getPaddingBoxPath(), Region.Op.DIFFERENCE);
|
||||
canvas.clipPath(paddingBoxPath(), Region.Op.DIFFERENCE);
|
||||
|
||||
final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
|
||||
int colorStart = getBorderColor(Spacing.START);
|
||||
@@ -1317,7 +1304,7 @@ public class CSSBackgroundDrawable extends Drawable {
|
||||
return CSSBackgroundDrawable.colorFromAlphaAndRGBComponents(alpha, rgb);
|
||||
}
|
||||
|
||||
private RectF getDirectionAwareBorderInsets() {
|
||||
public RectF getDirectionAwareBorderInsets() {
|
||||
final float borderWidth = getBorderWidthOrDefaultTo(0, Spacing.ALL);
|
||||
final float borderTopWidth = getBorderWidthOrDefaultTo(borderWidth, Spacing.TOP);
|
||||
final float borderBottomWidth = getBorderWidthOrDefaultTo(borderWidth, Spacing.BOTTOM);
|
||||
|
||||
+91
-10
@@ -16,6 +16,7 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.view.MotionEvent;
|
||||
@@ -26,6 +27,7 @@ import android.view.animation.Animation;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactNoCrashSoftException;
|
||||
import com.facebook.react.bridge.ReactSoftExceptionLogger;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
@@ -35,6 +37,7 @@ import com.facebook.react.modules.i18nmanager.I18nUtil;
|
||||
import com.facebook.react.touch.OnInterceptTouchEventListener;
|
||||
import com.facebook.react.touch.ReactHitSlopView;
|
||||
import com.facebook.react.touch.ReactInterceptingViewGroup;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.LengthPercentage;
|
||||
import com.facebook.react.uimanager.MeasureSpecAssertions;
|
||||
import com.facebook.react.uimanager.PointerEvents;
|
||||
@@ -44,13 +47,15 @@ import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
|
||||
import com.facebook.react.uimanager.ReactOverflowViewWithInset;
|
||||
import com.facebook.react.uimanager.ReactPointerEventsView;
|
||||
import com.facebook.react.uimanager.ReactZIndexedViewGroup;
|
||||
import com.facebook.react.uimanager.RootView;
|
||||
import com.facebook.react.uimanager.RootViewUtil;
|
||||
import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.facebook.react.uimanager.common.ViewUtil;
|
||||
import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable;
|
||||
import com.facebook.react.uimanager.style.BorderRadiusProp;
|
||||
import java.util.Objects;
|
||||
import com.facebook.react.uimanager.style.ComputedBorderRadius;
|
||||
|
||||
/**
|
||||
* Backing for a React View. Has support for borders, but since borders aren't common, lazy
|
||||
@@ -124,6 +129,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
private @Nullable OnInterceptTouchEventListener mOnInterceptTouchEventListener;
|
||||
private boolean mNeedsOffscreenAlphaCompositing;
|
||||
private @Nullable ViewGroupDrawingOrderHelper mDrawingOrderHelper;
|
||||
private @Nullable Path mPath;
|
||||
private float mBackfaceOpacity;
|
||||
private String mBackfaceVisibility;
|
||||
|
||||
@@ -152,6 +158,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
mOnInterceptTouchEventListener = null;
|
||||
mNeedsOffscreenAlphaCompositing = false;
|
||||
mDrawingOrderHelper = null;
|
||||
mPath = null;
|
||||
mBackfaceOpacity = 1.f;
|
||||
mBackfaceVisibility = "visible";
|
||||
}
|
||||
@@ -843,18 +850,25 @@ public class ReactViewGroup extends ViewGroup
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (mCSSBackgroundDrawable != null
|
||||
&& (Objects.equals(mOverflow, ViewProps.HIDDEN)
|
||||
|| Objects.equals(mOverflow, ViewProps.SCROLL))) {
|
||||
@Nullable Path paddingBoxPath = mCSSBackgroundDrawable.getPaddingBoxPath();
|
||||
if (paddingBoxPath != null) {
|
||||
canvas.clipPath(paddingBoxPath);
|
||||
try {
|
||||
dispatchOverflowDraw(canvas);
|
||||
super.dispatchDraw(canvas);
|
||||
} catch (NullPointerException | StackOverflowError e) {
|
||||
// Adding special exception management for StackOverflowError for logging purposes.
|
||||
// This will be removed in the future.
|
||||
RootView rootView = RootViewUtil.getRootView(ReactViewGroup.this);
|
||||
if (rootView != null) {
|
||||
rootView.handleException(e);
|
||||
} else {
|
||||
canvas.clipRect(mCSSBackgroundDrawable.getPaddingBoxRect());
|
||||
if (getContext() instanceof ReactContext) {
|
||||
ReactContext reactContext = (ReactContext) getContext();
|
||||
reactContext.handleException(
|
||||
new IllegalViewOperationException("StackOverflowException", this, e));
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.dispatchDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -873,6 +887,73 @@ public class ReactViewGroup extends ViewGroup
|
||||
return result;
|
||||
}
|
||||
|
||||
private void dispatchOverflowDraw(Canvas canvas) {
|
||||
if (mOverflow != null) {
|
||||
switch (mOverflow) {
|
||||
case ViewProps.VISIBLE:
|
||||
if (mPath != null) {
|
||||
mPath.rewind();
|
||||
}
|
||||
break;
|
||||
case ViewProps.HIDDEN:
|
||||
case ViewProps.SCROLL:
|
||||
float left = 0f;
|
||||
float top = 0f;
|
||||
float right = getWidth();
|
||||
float bottom = getHeight();
|
||||
|
||||
boolean hasClipPath = false;
|
||||
|
||||
if (mCSSBackgroundDrawable != null) {
|
||||
final RectF borderWidth = mCSSBackgroundDrawable.getDirectionAwareBorderInsets();
|
||||
|
||||
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 ComputedBorderRadius borderRadius =
|
||||
mCSSBackgroundDrawable.getComputedBorderRadius();
|
||||
|
||||
if (borderRadius.hasRoundedBorders()) {
|
||||
if (mPath == null) {
|
||||
mPath = new Path();
|
||||
}
|
||||
|
||||
mPath.rewind();
|
||||
mPath.addRoundRect(
|
||||
new RectF(left, top, right, bottom),
|
||||
new float[] {
|
||||
Math.max(borderRadius.getTopLeft() - borderWidth.left, 0),
|
||||
Math.max(borderRadius.getTopLeft() - borderWidth.top, 0),
|
||||
Math.max(borderRadius.getTopRight() - borderWidth.right, 0),
|
||||
Math.max(borderRadius.getTopRight() - borderWidth.top, 0),
|
||||
Math.max(borderRadius.getBottomRight() - borderWidth.right, 0),
|
||||
Math.max(borderRadius.getBottomRight() - borderWidth.bottom, 0),
|
||||
Math.max(borderRadius.getBottomLeft() - borderWidth.left, 0),
|
||||
Math.max(borderRadius.getBottomLeft() - borderWidth.bottom, 0),
|
||||
},
|
||||
Path.Direction.CW);
|
||||
canvas.clipPath(mPath);
|
||||
hasClipPath = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasClipPath) {
|
||||
canvas.clipRect(new RectF(left, top, right, bottom));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOpacityIfPossible(float opacity) {
|
||||
mBackfaceOpacity = opacity;
|
||||
setBackfaceVisibilityDependantOpacity();
|
||||
|
||||
@@ -12,11 +12,9 @@
|
||||
|
||||
import type {RNTesterModule} from '../../types/RNTesterTypes';
|
||||
|
||||
import hotdog from '../../assets/hotdog.jpg';
|
||||
import * as React from 'react';
|
||||
import {
|
||||
DynamicColorIOS,
|
||||
Image,
|
||||
Platform,
|
||||
PlatformColor,
|
||||
StyleSheet,
|
||||
@@ -216,23 +214,6 @@ const styles = StyleSheet.create({
|
||||
? DynamicColorIOS({light: 'magenta', dark: 'cyan'})
|
||||
: 'black',
|
||||
},
|
||||
borderWithoutClipping: {
|
||||
borderWidth: 10,
|
||||
overflow: 'visible',
|
||||
},
|
||||
borderWithClipping: {
|
||||
borderWidth: 10,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
borderWithClippingAndRadius: {
|
||||
borderWidth: 10,
|
||||
borderRadius: 30,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
hotdog: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
});
|
||||
|
||||
export default ({
|
||||
@@ -496,50 +477,5 @@ export default ({
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Child without clipping',
|
||||
name: 'child-no-clipping',
|
||||
description:
|
||||
'"overflow: visible" will cause child content to show above borders',
|
||||
render: function (): React.Node {
|
||||
return (
|
||||
<View
|
||||
testID="border-test-child-no-clipping"
|
||||
style={[styles.box, styles.borderWithoutClipping]}>
|
||||
<Image source={hotdog} style={styles.hotdog} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Child clipping',
|
||||
name: 'child-clipping',
|
||||
description:
|
||||
'"overflow: hidden" will cause child content to be clipped to borders',
|
||||
render: function (): React.Node {
|
||||
return (
|
||||
<View
|
||||
testID="border-test-child-clipping"
|
||||
style={[styles.box, styles.borderWithClipping]}>
|
||||
<Image source={hotdog} style={styles.hotdog} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Child clipping with radius',
|
||||
name: 'child-clipping-radius',
|
||||
description:
|
||||
'"overflow: hidden" will cause child content to be clipped to rounded corners',
|
||||
render: function (): React.Node {
|
||||
return (
|
||||
<View
|
||||
testID="border-test-child-clipping-radius"
|
||||
style={[styles.box, styles.borderWithClippingAndRadius]}>
|
||||
<Image source={hotdog} style={styles.hotdog} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
}: RNTesterModule);
|
||||
|
||||
Reference in New Issue
Block a user