Decouple background color from border drawing (#46190)

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

Right now the background color is tightly coupled with border drawing. For starters, I find this a bit confusing as one would not assume they are very closely related. But this also causes a bug around not being able to properly clip to the padding box, because if we did this we would clip the background color and transparent borders would look wrong.

This would also block a fix related to how borders display with clipped content that is coming in the later diffs. If we decide to use the border image, then we cannot properly display things like images since they would be on top of this image (otherwise background color shows through).

Changelog: [Internal]

Reviewed By: lenaic

Differential Revision: D61248625

fbshipit-source-id: ad398bbcfb69edc7d61362920773b51abea81d08
This commit is contained in:
Joe Vilches
2024-08-30 02:00:19 -07:00
committed by Facebook GitHub Bot
parent 2176866eb5
commit 7653f7600e
@@ -28,8 +28,11 @@
using namespace facebook::react;
const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
@implementation RCTViewComponentView {
UIColor *_backgroundColor;
CALayer *_backgroundColorLayer;
__weak CALayer *_borderLayer;
CALayer *_boxShadowLayer;
CALayer *_filterLayer;
@@ -524,6 +527,10 @@ using namespace facebook::react;
_containerView.frame = CGRectMake(0, 0, self.layer.bounds.size.width, self.layer.bounds.size.height);
}
if (_backgroundColorLayer) {
_backgroundColorLayer.frame = CGRectMake(0, 0, self.layer.bounds.size.width, self.layer.bounds.size.height);
}
if ((_props->transformOrigin.isSet() || _props->transform.operations.size() > 0) &&
layoutMetrics.frame.size != oldLayoutMetrics.frame.size) {
auto newTransform = _props->resolveTransform(layoutMetrics);
@@ -774,8 +781,6 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
[self setHoverStyle:hoverStyle];
}
#endif
// Stage 2. Border Rendering
const bool useCoreAnimationBorderRendering =
borderMetrics.borderColors.isUniform() && borderMetrics.borderWidths.isUniform() &&
borderMetrics.borderStyles.isUniform() && borderMetrics.borderRadii.isUniform() &&
@@ -787,8 +792,35 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
(colorComponentsFromColor(borderMetrics.borderColors.left).alpha == 0 &&
(*borderMetrics.borderColors.left).getUIColor() != nullptr));
// background color
CGColorRef backgroundColor = [_backgroundColor resolvedColorWithTraitCollection:self.traitCollection].CGColor;
// The reason we sometimes do not set self.layer's backgroundColor is because
// we want to support non-uniform border radii, which apple does not natively
// support. To get this behavior we need to create a CGPath in the shape that
// we want. If we mask self.layer to this path, we would be clipping subviews
// which we may not want to do. The generalized solution in this case is just
// create a new layer
if (useCoreAnimationBorderRendering) {
[_backgroundColorLayer removeFromSuperlayer];
_backgroundColorLayer = nil;
layer.backgroundColor = backgroundColor;
} else {
layer.backgroundColor = nil;
if (!_backgroundColorLayer) {
_backgroundColorLayer = [CALayer layer];
_backgroundColorLayer.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
_backgroundColorLayer.zPosition = BACKGROUND_COLOR_ZPOSITION;
[self.layer addSublayer:_backgroundColorLayer];
}
CAShapeLayer *maskLayer = [self
createMaskLayer:self.bounds
cornerInsets:RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero)];
_backgroundColorLayer.backgroundColor = backgroundColor;
_backgroundColorLayer.mask = maskLayer;
}
// Stage 2. Border Rendering
if (useCoreAnimationBorderRendering) {
layer.mask = nil;
[_borderLayer removeFromSuperlayer];
@@ -798,21 +830,17 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
layer.borderColor = borderColor;
CGColorRelease(borderColor);
layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft.horizontal;
layer.cornerCurve = CornerCurveFromBorderCurve(borderMetrics.borderCurves.topLeft);
layer.backgroundColor = backgroundColor;
} else {
if (!_borderLayer) {
CALayer *borderLayer = [CALayer new];
borderLayer.zPosition = -1024.0f;
borderLayer.zPosition = BACKGROUND_COLOR_ZPOSITION + 1;
borderLayer.frame = layer.bounds;
borderLayer.magnificationFilter = kCAFilterNearest;
[layer addSublayer:borderLayer];
_borderLayer = borderLayer;
}
layer.backgroundColor = nil;
layer.borderWidth = 0;
layer.borderColor = nil;
layer.cornerRadius = 0;
@@ -824,8 +852,8 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii),
RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths),
borderColors,
backgroundColor,
self.clipsToBounds);
[UIColor clearColor].CGColor,
NO);
RCTReleaseRCTBorderColors(borderColors);
@@ -959,8 +987,7 @@ static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle)
gradientLayer.mask = maskLayer;
}
// border layer should appear above gradient layers to make sure that the border is visible
gradientLayer.zPosition = _borderLayer.zPosition - 1;
gradientLayer.zPosition = BACKGROUND_COLOR_ZPOSITION;
[self.layer addSublayer:gradientLayer];
[_gradientLayers addObject:gradientLayer];