From 9f84b13f057cb897563202f06c9c54768d240247 Mon Sep 17 00:00:00 2001 From: Dawid Date: Mon, 12 Aug 2024 09:20:23 +0200 Subject: [PATCH 1/4] fix borders issue on Fabric --- .../ComponentViews/View/RCTViewComponentView.mm | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 93340509beb018..71a9cf41011096 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -662,7 +662,7 @@ - (void)invalidateLayer borderMetrics.borderWidths.left == 0 || self.clipsToBounds || (colorComponentsFromColor(borderMetrics.borderColors.left).alpha == 0 && (*borderMetrics.borderColors.left).getUIColor() != nullptr)); - + CGColorRef backgroundColor = [_backgroundColor resolvedColorWithTraitCollection:self.traitCollection].CGColor; if (useCoreAnimationBorderRendering) { @@ -681,7 +681,7 @@ - (void)invalidateLayer } else { if (!_borderLayer) { CALayer *borderLayer = [CALayer new]; - borderLayer.zPosition = -1024.0f; + borderLayer.zPosition = 1024.0f; borderLayer.frame = layer.bounds; borderLayer.magnificationFilter = kCAFilterNearest; [layer addSublayer:borderLayer]; @@ -694,14 +694,16 @@ - (void)invalidateLayer layer.cornerRadius = 0; RCTBorderColors borderColors = RCTCreateRCTBorderColorsFromBorderColors(borderMetrics.borderColors); - + UIColor *transparentColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0]; // 50% transparent red + CGColorRef transparentBackgroundColor = [transparentColor resolvedColorWithTraitCollection:self.traitCollection].CGColor; + UIImage *image = RCTGetBorderImage( RCTBorderStyleFromBorderStyle(borderMetrics.borderStyles.left), layer.bounds.size, RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths), borderColors, - backgroundColor, + transparentBackgroundColor, self.clipsToBounds); RCTReleaseRCTBorderColors(borderColors); @@ -714,9 +716,9 @@ - (void)invalidateLayer CGRect contentsCenter = CGRect{ CGPoint{imageCapInsets.left / imageSize.width, imageCapInsets.top / imageSize.height}, CGSize{(CGFloat)1.0 / imageSize.width, (CGFloat)1.0 / imageSize.height}}; - - _borderLayer.contents = (id)image.CGImage; - _borderLayer.contentsScale = image.scale; + + _borderLayer.contents = (id)image.CGImage; + _borderLayer.contentsScale = image.scale; BOOL isResizable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero); if (isResizable) { @@ -751,6 +753,7 @@ - (void)invalidateLayer } layer.cornerRadius = cornerRadius; + layer.backgroundColor = backgroundColor; layer.mask = maskLayer; } From fa06485118f465ec378e8b99008c280412adf8e9 Mon Sep 17 00:00:00 2001 From: Dawid Date: Mon, 12 Aug 2024 09:38:36 +0200 Subject: [PATCH 2/4] remove comment --- .../Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 71a9cf41011096..febac493d45cb0 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -694,7 +694,7 @@ - (void)invalidateLayer layer.cornerRadius = 0; RCTBorderColors borderColors = RCTCreateRCTBorderColorsFromBorderColors(borderMetrics.borderColors); - UIColor *transparentColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0]; // 50% transparent red + UIColor *transparentColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0]; CGColorRef transparentBackgroundColor = [transparentColor resolvedColorWithTraitCollection:self.traitCollection].CGColor; UIImage *image = RCTGetBorderImage( From 24cbbffc4e3ce396ef28a179bb2688f58c4dcd26 Mon Sep 17 00:00:00 2001 From: Dawid Date: Mon, 12 Aug 2024 13:45:56 +0200 Subject: [PATCH 3/4] creating transparentColor with UIColor clearColor --- .../Mounting/ComponentViews/View/RCTViewComponentView.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index febac493d45cb0..88a035b344c7fa 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -694,7 +694,7 @@ - (void)invalidateLayer layer.cornerRadius = 0; RCTBorderColors borderColors = RCTCreateRCTBorderColorsFromBorderColors(borderMetrics.borderColors); - UIColor *transparentColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0]; + UIColor *transparentColor = [UIColor clearColor]; CGColorRef transparentBackgroundColor = [transparentColor resolvedColorWithTraitCollection:self.traitCollection].CGColor; UIImage *image = RCTGetBorderImage( @@ -717,8 +717,8 @@ - (void)invalidateLayer CGPoint{imageCapInsets.left / imageSize.width, imageCapInsets.top / imageSize.height}, CGSize{(CGFloat)1.0 / imageSize.width, (CGFloat)1.0 / imageSize.height}}; - _borderLayer.contents = (id)image.CGImage; - _borderLayer.contentsScale = image.scale; + _borderLayer.contents = (id)image.CGImage; + _borderLayer.contentsScale = image.scale; BOOL isResizable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero); if (isResizable) { From e5477b4460f8548a06c424a69745f42e9bab8d5b Mon Sep 17 00:00:00 2001 From: Dawid Date: Tue, 13 Aug 2024 16:24:19 +0200 Subject: [PATCH 4/4] clipping image --- .../View/RCTViewComponentView.mm | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 88a035b344c7fa..b8f04f42f1f2c5 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -681,7 +681,7 @@ - (void)invalidateLayer } else { if (!_borderLayer) { CALayer *borderLayer = [CALayer new]; - borderLayer.zPosition = 1024.0f; + borderLayer.zPosition = -1024.0f; borderLayer.frame = layer.bounds; borderLayer.magnificationFilter = kCAFilterNearest; [layer addSublayer:borderLayer]; @@ -694,16 +694,13 @@ - (void)invalidateLayer layer.cornerRadius = 0; RCTBorderColors borderColors = RCTCreateRCTBorderColorsFromBorderColors(borderMetrics.borderColors); - UIColor *transparentColor = [UIColor clearColor]; - CGColorRef transparentBackgroundColor = [transparentColor resolvedColorWithTraitCollection:self.traitCollection].CGColor; - UIImage *image = RCTGetBorderImage( RCTBorderStyleFromBorderStyle(borderMetrics.borderStyles.left), layer.bounds.size, RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths), borderColors, - transparentBackgroundColor, + backgroundColor, self.clipsToBounds); RCTReleaseRCTBorderColors(borderColors); @@ -740,21 +737,24 @@ - (void)invalidateLayer // In this case we can simply use `cornerRadius` exclusively. cornerRadius = borderMetrics.borderRadii.topLeft; } else { - // In this case we have to generate masking layer manually. - CGPathRef path = RCTPathCreateWithRoundedRect( - self.bounds, - RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero), - nil); - - maskLayer = [CAShapeLayer layer]; - maskLayer.path = path; - CGPathRelease(path); + RCTCornerInsets cornerInsets = RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero); + maskLayer = [self createMaskLayer:self.bounds cornerInsets:cornerInsets]; } } - layer.cornerRadius = cornerRadius; - layer.backgroundColor = backgroundColor; - layer.mask = maskLayer; + layer.cornerRadius = cornerRadius; + layer.mask = maskLayer; + + for (UIView *subview in self.subviews) { + if ([subview isKindOfClass:[UIImageView class]]) { + RCTCornerInsets cornerInsets = RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), RCTUIEdgeInsetsFromEdgeInsets(borderMetrics.borderWidths)); + + // If the subview is an image view, we have to apply the mask directly to the image view's layer, + // otherwise the image might overflow with the border radius. + subview.layer.mask = [self createMaskLayer:subview.bounds cornerInsets:cornerInsets]; + } + } + } [_filterLayer removeFromSuperlayer]; @@ -849,6 +849,18 @@ - (void)invalidateLayer } } +- (CAShapeLayer *)createMaskLayer:(CGRect)bounds cornerInsets:(RCTCornerInsets)cornerInsets +{ + CGPathRef path = RCTPathCreateWithRoundedRect( + bounds, + cornerInsets, + nil); + CAShapeLayer *maskLayer = [CAShapeLayer layer]; + maskLayer.path = path; + CGPathRelease(path); + return maskLayer; +} + #pragma mark - Accessibility - (NSObject *)accessibilityElement