Skip to content

Commit

Permalink
Decouple background color from border drawing (facebook#46190)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#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
  • Loading branch information
joevilches authored and facebook-github-bot committed Aug 26, 2024
1 parent 54a3ed6 commit 8715b57
Showing 1 changed file with 38 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -524,6 +527,10 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
_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);
Expand Down Expand Up @@ -774,8 +781,6 @@ - (void)invalidateLayer
[self setHoverStyle:hoverStyle];
}
#endif

// Stage 2. Border Rendering
const bool useCoreAnimationBorderRendering =
borderMetrics.borderColors.isUniform() && borderMetrics.borderWidths.isUniform() &&
borderMetrics.borderStyles.isUniform() && borderMetrics.borderRadii.isUniform() &&
Expand All @@ -787,8 +792,35 @@ - (void)invalidateLayer
(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];
Expand All @@ -798,21 +830,17 @@ - (void)invalidateLayer
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;
Expand All @@ -824,8 +852,8 @@ - (void)invalidateLayer
RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii),
RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths),
borderColors,
backgroundColor,
self.clipsToBounds);
[UIColor clearColor].CGColor,
NO);

RCTReleaseRCTBorderColors(borderColors);

Expand Down Expand Up @@ -959,8 +987,7 @@ - (void)invalidateLayer
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];
Expand Down

0 comments on commit 8715b57

Please sign in to comment.