Skip to content

Commit

Permalink
Explain Apple bug
Browse files Browse the repository at this point in the history
  • Loading branch information
Saadnajmi committed Feb 22, 2024
1 parent e57015f commit 878cc34
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -603,15 +603,23 @@ - (void)invalidateLayer
if (@available(iOS 17.0, *)) {
UIHoverStyle *hoverStyle = nil;
if ([_cursor isEqual:@"pointer"]) {
CGPathRef borderPath = RCTPathCreateWithRoundedRect(self.bounds, cornerInsets, nil);
#if TARGET_OS_IOS
// Due to an Apple bug, it seems on iOS, `[UIShape shapeWithBezierPath:]` needs to
// be calculated in the superviews' coordinate space (view.frame). This is not true
// on other platforms like visionOS. Unfortunately, this bug persists if you run an
// iPad app on compatibility mode on visionOS.
CGPathRef borderPath = RCTPathCreateWithRoundedRect(self.frame, cornerInsets, NULL);
#else // TARGET_OS_VISION
CGPathRef borderPath = RCTPathCreateWithRoundedRect(self.bounds, cornerInsets, NULL);
#endif
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithCGPath:borderPath];
CGPathRelease(borderPath);
UIShape *shape = [UIShape shapeWithBezierPath:bezierPath];

hoverStyle = [UIHoverStyle styleWithEffect:[UIHoverHighlightEffect effect] shape:shape];
}
[self setHoverStyle:hoverStyle];
}


// Stage 2. Border Rendering
const bool useCoreAnimationBorderRendering =
Expand Down
41 changes: 26 additions & 15 deletions packages/react-native/React/Views/RCTView.m
Original file line number Diff line number Diff line change
Expand Up @@ -864,14 +864,6 @@ - (void)displayLayer:(CALayer *)layer
[self updateClippingForLayer:layer];
}

CGPathRef RCTBorderPathForView(RCTView *view)
{
const RCTCornerRadii cornerRadii = [view cornerRadii];
const RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero);
CGPathRef borderPath = RCTPathCreateWithRoundedRect(view.bounds, cornerInsets, NULL);
return borderPath;
}

static BOOL RCTLayerHasShadow(CALayer *layer)
{
return layer.shadowOpacity * CGColorGetAlpha(layer.shadowColor) > 0;
Expand All @@ -882,7 +874,9 @@ static void RCTUpdateShadowPathForView(RCTView *view)
if (RCTLayerHasShadow(view.layer)) {
if (CGColorGetAlpha(view.backgroundColor.CGColor) > 0.999) {
// If view has a solid background color, calculate shadow path from border
CGPathRef shadowPath = RCTBorderPathForView(view);
const RCTCornerRadii cornerRadii = [view cornerRadii];
const RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero);
CGPathRef shadowPath = RCTPathCreateWithRoundedRect(view.bounds, cornerInsets, NULL);
view.layer.shadowPath = shadowPath;
CGPathRelease(shadowPath);

Expand All @@ -905,8 +899,18 @@ static void RCTUpdateHoverStyleForView(RCTView *view)
if (@available(iOS 17.0, *)) {
UIHoverStyle *hoverStyle = nil;
if ([view cursor] == RCTCursorPointer) {
CGPathRef borderPath = RCTBorderPathForView(view);
const RCTCornerRadii cornerRadii = [view cornerRadii];
const RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero);
#if TARGET_OS_IOS
// Due to an Apple bug, it seems on iOS, `[UIShape shapeWithBezierPath:]` needs to
// be calculated in the superviews' coordinate space (view.frame). This is not true
// on other platforms like visionOS.
CGPathRef borderPath = RCTPathCreateWithRoundedRect(view.frame, cornerInsets, NULL);
#else // TARGET_OS_VISION
CGPathRef borderPath = RCTPathCreateWithRoundedRect(view.bounds, cornerInsets, NULL);
#endif
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithCGPath:borderPath];
CGPathRelease(borderPath);
UIShape *shape = [UIShape shapeWithBezierPath:bezierPath];

hoverStyle = [UIHoverStyle styleWithEffect:[UIHoverHighlightEffect effect] shape:shape];
Expand All @@ -921,11 +925,18 @@ - (void)updateClippingForLayer:(CALayer *)layer
CGFloat cornerRadius = 0;

if (self.clipsToBounds) {
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
CGPathRef path = RCTBorderPathForView(self);
shapeLayer.path = path;
CGPathRelease(path);
mask = shapeLayer;
const RCTCornerRadii cornerRadii = [self cornerRadii];
if (RCTCornerRadiiAreEqual(cornerRadii)) {
cornerRadius = cornerRadii.topLeft;

} else {
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
CGPathRef path =
RCTPathCreateWithRoundedRect(self.bounds, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL);
shapeLayer.path = path;
CGPathRelease(path);
mask = shapeLayer;
}
}

layer.cornerRadius = cornerRadius;
Expand Down

0 comments on commit 878cc34

Please sign in to comment.