Skip to content

Commit 6291ff0

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Remove ReactViewGroup Legacy Background Path (facebook#46159)
Summary: Pull Request resolved: facebook#46159 ## This Diff This removes the legacy path from ReactViewGroup and its view manager. ## This Stack This removes the non-Style-applicator background management paths of the different native components. There have been multiple conflicting changes, and bugs added bc harder to reason about, which motivates making this change as soon as possible. This also lets us formalize guarantees that BaseViewManager may safely manipulate background styling of all built in native components. There is one still known issue, where BackgroundStyleApplicator does not propagate I18nManager derived layout direction to borders (compared to Android derived root direction). This is mostly an issue for apps that with LTR and RTL context, or force a layout direction, which I would guess is relatively rare, so my plan is to forward fix this later this by enabling set_android_layout_direction which will solve that problem mopre generically. Changelog: [Internal] Reviewed By: tdn120 Differential Revision: D61657251 fbshipit-source-id: 6d00a1cac79450d306cf28446e6397d31ceffb19
1 parent 890970a commit 6291ff0

File tree

3 files changed

+31
-266
lines changed

3 files changed

+31
-266
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -327,13 +327,6 @@ public float getInnerBorderRadius(float computedRadius, float borderWidth) {
327327
return Math.max(computedRadius - borderWidth, 0);
328328
}
329329

330-
// TODO: This API is unsafe and should be removed when
331-
// BackgroundStyleApplicator is rolled out
332-
@Deprecated(forRemoval = true, since = "0.76.0")
333-
public ComputedBorderRadius getComputedBorderRadius() {
334-
return mComputedBorderRadius;
335-
}
336-
337330
public void setColor(int color) {
338331
mColor = color;
339332
invalidateSelf();

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java

Lines changed: 19 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818
import android.graphics.Paint;
1919
import android.graphics.Path;
2020
import android.graphics.Rect;
21-
import android.graphics.RectF;
2221
import android.graphics.drawable.Drawable;
23-
import android.graphics.drawable.LayerDrawable;
2422
import android.os.Build;
2523
import android.view.MotionEvent;
2624
import android.view.View;
@@ -31,20 +29,16 @@
3129
import com.facebook.common.logging.FLog;
3230
import com.facebook.infer.annotation.Assertions;
3331
import com.facebook.react.R;
34-
import com.facebook.react.bridge.ReactContext;
3532
import com.facebook.react.bridge.ReactNoCrashSoftException;
3633
import com.facebook.react.bridge.ReactSoftExceptionLogger;
3734
import com.facebook.react.bridge.UiThreadUtil;
38-
import com.facebook.react.common.annotations.UnstableReactNativeAPI;
3935
import com.facebook.react.common.annotations.VisibleForTesting;
4036
import com.facebook.react.config.ReactFeatureFlags;
4137
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
42-
import com.facebook.react.modules.i18nmanager.I18nUtil;
4338
import com.facebook.react.touch.OnInterceptTouchEventListener;
4439
import com.facebook.react.touch.ReactHitSlopView;
4540
import com.facebook.react.touch.ReactInterceptingViewGroup;
4641
import com.facebook.react.uimanager.BackgroundStyleApplicator;
47-
import com.facebook.react.uimanager.IllegalViewOperationException;
4842
import com.facebook.react.uimanager.LengthPercentage;
4943
import com.facebook.react.uimanager.LengthPercentageType;
5044
import com.facebook.react.uimanager.MeasureSpecAssertions;
@@ -56,20 +50,14 @@
5650
import com.facebook.react.uimanager.ReactOverflowViewWithInset;
5751
import com.facebook.react.uimanager.ReactPointerEventsView;
5852
import com.facebook.react.uimanager.ReactZIndexedViewGroup;
59-
import com.facebook.react.uimanager.RootView;
60-
import com.facebook.react.uimanager.RootViewUtil;
6153
import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper;
6254
import com.facebook.react.uimanager.common.UIManagerType;
6355
import com.facebook.react.uimanager.common.ViewUtil;
6456
import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable;
65-
import com.facebook.react.uimanager.style.BackgroundImageLayer;
6657
import com.facebook.react.uimanager.style.BorderRadiusProp;
6758
import com.facebook.react.uimanager.style.BorderStyle;
68-
import com.facebook.react.uimanager.style.ComputedBorderRadius;
69-
import com.facebook.react.uimanager.style.CornerRadii;
7059
import com.facebook.react.uimanager.style.LogicalEdge;
7160
import com.facebook.react.uimanager.style.Overflow;
72-
import java.util.List;
7361

7462
/**
7563
* Backing for a React View. Has support for borders, but since borders aren't common, lazy
@@ -238,44 +226,12 @@ public void dispatchProvideStructure(ViewStructure structure) {
238226

239227
@Override
240228
public void setBackgroundColor(int color) {
241-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
242-
BackgroundStyleApplicator.setBackgroundColor(this, color);
243-
} else {
244-
if (color == Color.TRANSPARENT && mCSSBackgroundDrawable == null) {
245-
// don't do anything, no need to allocate ReactBackgroundDrawable for transparent background
246-
} else {
247-
getOrCreateReactViewBackground().setColor(color);
248-
}
249-
}
250-
}
251-
252-
@UnstableReactNativeAPI
253-
/*package*/ void setBackgroundImage(@Nullable List<BackgroundImageLayer> backgroundImageLayers) {
254-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
255-
BackgroundStyleApplicator.setBackgroundImage(this, backgroundImageLayers);
256-
} else {
257-
getOrCreateReactViewBackground().setBackgroundImage(backgroundImageLayers);
258-
}
229+
BackgroundStyleApplicator.setBackgroundColor(this, color);
259230
}
260231

261232
@Deprecated(since = "0.76.0", forRemoval = true)
262233
public void setTranslucentBackgroundDrawable(@Nullable Drawable background) {
263-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
264-
BackgroundStyleApplicator.setFeedbackUnderlay(this, background);
265-
} else {
266-
// it's required to call setBackground to null, as in some of the cases we may set new
267-
// background to be a layer drawable that contains a drawable that has been setup
268-
// as a background previously. This will not work correctly as the drawable callback logic is
269-
// messed up in AOSP
270-
updateBackgroundDrawable(null);
271-
if (mCSSBackgroundDrawable != null && background != null) {
272-
LayerDrawable layerDrawable =
273-
new LayerDrawable(new Drawable[] {mCSSBackgroundDrawable, background});
274-
updateBackgroundDrawable(layerDrawable);
275-
} else if (background != null) {
276-
updateBackgroundDrawable(background);
277-
}
278-
}
234+
BackgroundStyleApplicator.setFeedbackUnderlay(this, background);
279235
}
280236

281237
@Override
@@ -344,20 +300,12 @@ public void setNeedsOffscreenAlphaCompositing(boolean needsOffscreenAlphaComposi
344300
}
345301

346302
public void setBorderWidth(int position, float width) {
347-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
348-
BackgroundStyleApplicator.setBorderWidth(
349-
this, LogicalEdge.values()[position], PixelUtil.toDIPFromPixel(width));
350-
} else {
351-
getOrCreateReactViewBackground().setBorderWidth(position, width);
352-
}
303+
BackgroundStyleApplicator.setBorderWidth(
304+
this, LogicalEdge.values()[position], PixelUtil.toDIPFromPixel(width));
353305
}
354306

355307
public void setBorderColor(int position, @Nullable Integer color) {
356-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
357-
BackgroundStyleApplicator.setBorderColor(this, LogicalEdge.values()[position], color);
358-
} else {
359-
getOrCreateReactViewBackground().setBorderColor(position, color);
360-
}
308+
BackgroundStyleApplicator.setBorderColor(this, LogicalEdge.values()[position], color);
361309
}
362310

363311
/**
@@ -373,34 +321,21 @@ public void setBorderRadius(float borderRadius) {
373321
*/
374322
@Deprecated(since = "0.75.0", forRemoval = true)
375323
public void setBorderRadius(float borderRadius, int position) {
376-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
377-
@Nullable
378-
LengthPercentage radius =
379-
Float.isNaN(borderRadius)
380-
? null
381-
: new LengthPercentage(borderRadius, LengthPercentageType.POINT);
382-
BackgroundStyleApplicator.setBorderRadius(this, BorderRadiusProp.values()[position], radius);
383-
} else {
384-
getOrCreateReactViewBackground().setRadius(borderRadius, position);
385-
}
324+
@Nullable
325+
LengthPercentage radius =
326+
Float.isNaN(borderRadius)
327+
? null
328+
: new LengthPercentage(borderRadius, LengthPercentageType.POINT);
329+
BackgroundStyleApplicator.setBorderRadius(this, BorderRadiusProp.values()[position], radius);
386330
}
387331

388332
public void setBorderRadius(BorderRadiusProp property, @Nullable LengthPercentage borderRadius) {
389-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
390-
BackgroundStyleApplicator.setBorderRadius(this, property, borderRadius);
391-
} else {
392-
CSSBackgroundDrawable backgroundDrawable = getOrCreateReactViewBackground();
393-
backgroundDrawable.setBorderRadius(property, borderRadius);
394-
}
333+
BackgroundStyleApplicator.setBorderRadius(this, property, borderRadius);
395334
}
396335

397336
public void setBorderStyle(@Nullable String style) {
398-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
399-
BackgroundStyleApplicator.setBorderStyle(
400-
this, style == null ? null : BorderStyle.fromString(style));
401-
} else {
402-
getOrCreateReactViewBackground().setBorderStyle(style);
403-
}
337+
BackgroundStyleApplicator.setBorderStyle(
338+
this, style == null ? null : BorderStyle.fromString(style));
404339
}
405340

406341
@Override
@@ -861,39 +796,8 @@ private boolean needsIsolatedLayer() {
861796

862797
@VisibleForTesting
863798
public int getBackgroundColor() {
864-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
865-
@Nullable Integer color = BackgroundStyleApplicator.getBackgroundColor(this);
866-
return color == null ? DEFAULT_BACKGROUND_COLOR : color;
867-
} else {
868-
if (getBackground() != null) {
869-
return ((CSSBackgroundDrawable) getBackground()).getColor();
870-
}
871-
return DEFAULT_BACKGROUND_COLOR;
872-
}
873-
}
874-
875-
/* package */ CSSBackgroundDrawable getOrCreateReactViewBackground() {
876-
if (mCSSBackgroundDrawable == null) {
877-
mCSSBackgroundDrawable = new CSSBackgroundDrawable(getContext());
878-
Drawable backgroundDrawable = getBackground();
879-
updateBackgroundDrawable(
880-
null); // required so that drawable callback is cleared before we add the
881-
// drawable back as a part of LayerDrawable
882-
if (backgroundDrawable == null) {
883-
updateBackgroundDrawable(mCSSBackgroundDrawable);
884-
} else {
885-
LayerDrawable layerDrawable =
886-
new LayerDrawable(new Drawable[] {mCSSBackgroundDrawable, backgroundDrawable});
887-
updateBackgroundDrawable(layerDrawable);
888-
}
889-
if (!ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
890-
mCSSBackgroundDrawable.setLayoutDirectionOverride(
891-
I18nUtil.getInstance().isRTL(getContext())
892-
? LAYOUT_DIRECTION_RTL
893-
: LAYOUT_DIRECTION_LTR);
894-
}
895-
}
896-
return mCSSBackgroundDrawable;
799+
@Nullable Integer color = BackgroundStyleApplicator.getBackgroundColor(this);
800+
return color == null ? DEFAULT_BACKGROUND_COLOR : color;
897801
}
898802

899803
@Override
@@ -983,33 +887,10 @@ && needsIsolatedLayer()) {
983887

984888
@Override
985889
protected void dispatchDraw(Canvas canvas) {
986-
if (ReactNativeFeatureFlags.enableBackgroundStyleApplicator()) {
987-
if (mOverflow != Overflow.VISIBLE || getTag(R.id.filter) != null) {
988-
BackgroundStyleApplicator.clipToPaddingBox(this, canvas);
989-
}
990-
super.dispatchDraw(canvas);
991-
return;
992-
}
993-
994-
try {
995-
dispatchOverflowDraw(canvas);
996-
super.dispatchDraw(canvas);
997-
} catch (NullPointerException | StackOverflowError e) {
998-
// Adding special exception management for StackOverflowError for logging purposes.
999-
// This will be removed in the future.
1000-
RootView rootView = RootViewUtil.getRootView(ReactViewGroup.this);
1001-
if (rootView != null) {
1002-
rootView.handleException(e);
1003-
} else {
1004-
if (getContext() instanceof ReactContext) {
1005-
ReactContext reactContext = (ReactContext) getContext();
1006-
reactContext.handleException(
1007-
new IllegalViewOperationException("StackOverflowException", this, e));
1008-
} else {
1009-
throw e;
1010-
}
1011-
}
890+
if (mOverflow != Overflow.VISIBLE || getTag(R.id.filter) != null) {
891+
BackgroundStyleApplicator.clipToPaddingBox(this, canvas);
1012892
}
893+
super.dispatchDraw(canvas);
1013894
}
1014895

1015896
@Override
@@ -1048,83 +929,6 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
1048929
return result;
1049930
}
1050931

1051-
private void dispatchOverflowDraw(Canvas canvas) {
1052-
Overflow tempOverflow = mOverflow;
1053-
1054-
// If the view contains a filter, we clip to the padding box.
1055-
if (getTag(R.id.filter) != null) {
1056-
tempOverflow = Overflow.HIDDEN;
1057-
}
1058-
1059-
switch (tempOverflow) {
1060-
case VISIBLE:
1061-
if (mPath != null) {
1062-
mPath.rewind();
1063-
}
1064-
break;
1065-
case HIDDEN:
1066-
case SCROLL:
1067-
float left = 0f;
1068-
float top = 0f;
1069-
float right = getWidth();
1070-
float bottom = getHeight();
1071-
1072-
boolean hasClipPath = false;
1073-
1074-
if (mCSSBackgroundDrawable != null) {
1075-
final RectF borderWidth = mCSSBackgroundDrawable.getDirectionAwareBorderInsets();
1076-
1077-
if (borderWidth.top > 0
1078-
|| borderWidth.left > 0
1079-
|| borderWidth.bottom > 0
1080-
|| borderWidth.right > 0) {
1081-
left += borderWidth.left;
1082-
top += borderWidth.top;
1083-
right -= borderWidth.right;
1084-
bottom -= borderWidth.bottom;
1085-
}
1086-
1087-
final ComputedBorderRadius borderRadius =
1088-
mCSSBackgroundDrawable.getComputedBorderRadius();
1089-
1090-
if (borderRadius.hasRoundedBorders()) {
1091-
if (mPath == null) {
1092-
mPath = new Path();
1093-
}
1094-
1095-
CornerRadii topLeftRadius = borderRadius.getTopLeft().toPixelFromDIP();
1096-
CornerRadii topRightRadius = borderRadius.getTopRight().toPixelFromDIP();
1097-
CornerRadii bottomLeftRadius = borderRadius.getBottomLeft().toPixelFromDIP();
1098-
CornerRadii bottomRightRadius = borderRadius.getBottomRight().toPixelFromDIP();
1099-
1100-
mPath.rewind();
1101-
mPath.addRoundRect(
1102-
new RectF(left, top, right, bottom),
1103-
new float[] {
1104-
Math.max(topLeftRadius.getHorizontal() - borderWidth.left, 0),
1105-
Math.max(topLeftRadius.getVertical() - borderWidth.top, 0),
1106-
Math.max(topRightRadius.getHorizontal() - borderWidth.right, 0),
1107-
Math.max(topRightRadius.getVertical() - borderWidth.top, 0),
1108-
Math.max(bottomRightRadius.getHorizontal() - borderWidth.right, 0),
1109-
Math.max(bottomRightRadius.getVertical() - borderWidth.bottom, 0),
1110-
Math.max(bottomLeftRadius.getHorizontal() - borderWidth.left, 0),
1111-
Math.max(bottomLeftRadius.getVertical() - borderWidth.bottom, 0),
1112-
},
1113-
Path.Direction.CW);
1114-
canvas.clipPath(mPath);
1115-
hasClipPath = true;
1116-
}
1117-
}
1118-
1119-
if (!hasClipPath) {
1120-
canvas.clipRect(new RectF(left, top, right, bottom));
1121-
}
1122-
break;
1123-
default:
1124-
break;
1125-
}
1126-
}
1127-
1128932
public void setOpacityIfPossible(float opacity) {
1129933
mBackfaceOpacity = opacity;
1130934
setBackfaceVisibilityDependantOpacity();

0 commit comments

Comments
 (0)