From 27db9bcdcf3730ef21c592e007ab58430911df8e Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 1 Oct 2024 22:53:50 -0500 Subject: [PATCH 1/6] feat(RCTUIKit): Shim RCTUIGraphicsImageRenderer --- .../Libraries/Image/RCTImageBlurUtils.mm | 19 +++-- .../Libraries/Image/RCTImageUtils.mm | 18 ++--- packages/react-native/React/Base/RCTUIKit.h | 31 +++++++- .../react-native/React/Base/macOS/RCTUIKit.m | 73 +++++++++---------- .../React/Views/RCTBorderDrawing.m | 56 +++----------- .../RCTTest/FBSnapshotTestCase/UIImage+Diff.m | 22 +----- 6 files changed, 93 insertions(+), 126 deletions(-) diff --git a/packages/react-native/Libraries/Image/RCTImageBlurUtils.mm b/packages/react-native/Libraries/Image/RCTImageBlurUtils.mm index 889cb5ae629c1b..d4c31a96e2a6c4 100644 --- a/packages/react-native/Libraries/Image/RCTImageBlurUtils.mm +++ b/packages/react-native/Libraries/Image/RCTImageBlurUtils.mm @@ -25,23 +25,22 @@ // convert to ARGB if it isn't if (CGImageGetBitsPerPixel(imageRef) != 32 || !((CGImageGetBitmapInfo(imageRef) & kCGBitmapAlphaInfoMask))) { -#if !TARGET_OS_OSX // [macOS] - UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat]; - rendererFormat.scale = inputImage.scale; - UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:inputImage.size - format:rendererFormat]; + RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS] + rendererFormat.scale = UIImageGetScale(inputImage); // [macOS] + RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:inputImage.size // [macOS] + format:rendererFormat]; +#if !TARGET_OS_OSX // [macOS] imageRef = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { [inputImage drawAtPoint:CGPointZero]; }].CGImage; #else // [macOS - UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, imageScale); - [inputImage drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0]; - imageRef = (CGImageRef)CFAutorelease(CGBitmapContextCreateImage(UIGraphicsGetCurrentContext())); - UIGraphicsEndImageContext(); + NSImage *image = [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull context) { + [inputImage drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0]; + }]; + imageRef = UIImageGetCGImageRef(image); #endif // macOS] } - vImage_Buffer buffer1, buffer2; buffer1.width = buffer2.width = CGImageGetWidth(imageRef); buffer1.height = buffer2.height = CGImageGetHeight(imageRef); diff --git a/packages/react-native/Libraries/Image/RCTImageUtils.mm b/packages/react-native/Libraries/Image/RCTImageUtils.mm index 1a80c1e652498e..9945220e9a1028 100644 --- a/packages/react-native/Libraries/Image/RCTImageUtils.mm +++ b/packages/react-native/Libraries/Image/RCTImageUtils.mm @@ -382,25 +382,19 @@ BOOL RCTUpscalingRequired( } BOOL opaque = !RCTUIImageHasAlpha(image); // [macOS] -#if !TARGET_OS_OSX // [macOS] - UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat]; + RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS] rendererFormat.opaque = opaque; rendererFormat.scale = destScale; - UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:destSize + RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:destSize // [macOS] format:rendererFormat]; - return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + return [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull context) { // [macOS] CGContextConcatCTM(context.CGContext, transform); +#if !TARGET_OS_OSX // [macOS] [image drawAtPoint:CGPointZero]; - }]; #else // [macOS - UIGraphicsBeginImageContextWithOptions(destSize, opaque, destScale); - CGContextRef currentContext = UIGraphicsGetCurrentContext(); - CGContextConcatCTM(currentContext, transform); - [image drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0]; - UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return result; + [image drawAtPoint:CGPointZero fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0]; #endif // macOS] + }]; } BOOL RCTImageHasAlpha(CGImageRef image) diff --git a/packages/react-native/React/Base/RCTUIKit.h b/packages/react-native/React/Base/RCTUIKit.h index 4ea338501cd67b..8cd17e29b3ca41 100644 --- a/packages/react-native/React/Base/RCTUIKit.h +++ b/packages/react-native/React/Base/RCTUIKit.h @@ -269,9 +269,6 @@ extern "C" { // UIGraphics.h CGContextRef UIGraphicsGetCurrentContext(void); -void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale); -NSImage *UIGraphicsGetImageFromCurrentImageContext(void); -void UIGraphicsEndImageContext(void); CGImageRef UIImageGetCGImageRef(NSImage *image); #ifdef __cplusplus @@ -641,3 +638,31 @@ NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END @end #endif + +#if !TARGET_OS_OSX +typedef UIGraphicsImageRendererContext RCTUIGraphicsImageRendererContext; +typedef UIGraphicsImageDrawingActions RCTUIGraphicsImageDrawingActions; +typedef UIGraphicsImageRendererFormat RCTUIGraphicsImageRendererFormat; +typedef UIGraphicsImageRenderer RCTUIGraphicsImageRenderer; +#else +NS_ASSUME_NONNULL_BEGIN +typedef NSGraphicsContext RCTUIGraphicsImageRendererContext; +typedef void (^RCTUIGraphicsImageDrawingActions)(RCTUIGraphicsImageRendererContext *rendererContext); + +@interface RCTUIGraphicsImageRendererFormat : NSObject + ++ (instancetype)defaultFormat; + +@property (nonatomic) CGFloat scale; +@property (nonatomic) BOOL opaque; + +@end + +@interface RCTUIGraphicsImageRenderer : NSObject + +- (instancetype)initWithSize:(CGSize)size format:(RCTUIGraphicsImageRendererFormat *)format; +- (NSImage *)imageWithActions:(NS_NOESCAPE RCTUIGraphicsImageDrawingActions)actions; + +@end +NS_ASSUME_NONNULL_END +#endif diff --git a/packages/react-native/React/Base/macOS/RCTUIKit.m b/packages/react-native/React/Base/macOS/RCTUIKit.m index decd84cda4c88b..c55d39a2ae2958 100644 --- a/packages/react-native/React/Base/macOS/RCTUIKit.m +++ b/packages/react-native/React/Base/macOS/RCTUIKit.m @@ -32,37 +32,6 @@ CGContextRef UIGraphicsGetCurrentContext(void) return [[NSGraphicsContext currentContext] CGContext]; } -void UIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, CGFloat scale) -{ - if (scale == 0.0) - { - // TODO: Assert. We can't assume a display scale on macOS - scale = 1.0; - } - - size_t width = ceilf(size.width * scale); - size_t height = ceilf(size.height * scale); - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef ctx = CGBitmapContextCreate(NULL, width, height, 8/*bitsPerComponent*/, width * 4/*bytesPerRow*/, colorSpace, kCGImageAlphaPremultipliedFirst); - CGColorSpaceRelease(colorSpace); - - if (ctx != NULL) - { - // flip the context (top left at 0, 0) and scale it - CGContextTranslateCTM(ctx, 0.0, height); - CGContextScaleCTM(ctx, scale, -scale); - - NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES]; - objc_setAssociatedObject(graphicsContext, &RCTGraphicsContextSizeKey, [NSValue valueWithSize:size], OBJC_ASSOCIATION_COPY_NONATOMIC); - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:graphicsContext]; - - CFRelease(ctx); - } -} - NSImage *UIGraphicsGetImageFromCurrentImageContext(void) { NSImage *image = nil; @@ -83,12 +52,6 @@ void UIGraphicsBeginImageContextWithOptions(CGSize size, __unused BOOL opaque, C return image; } -void UIGraphicsEndImageContext(void) -{ - RCTAssert(objc_getAssociatedObject([NSGraphicsContext currentContext], &RCTGraphicsContextSizeKey), @"The current graphics context is not a React image context!"); - [NSGraphicsContext restoreGraphicsState]; -} - // // functionally equivalent types // @@ -1040,4 +1003,40 @@ - (void)setImage:(UIImage *)image @end +@implementation RCTUIGraphicsImageRendererFormat + ++ (nonnull instancetype)defaultFormat { + static dispatch_once_t token = 0; + static RCTUIGraphicsImageRendererFormat *_sharedObject = nil; + dispatch_once(&token, ^{ + _sharedObject = [[self alloc] init]; + }); + return _sharedObject; +} + +@end + +@implementation RCTUIGraphicsImageRenderer +{ + CGSize _size; +} + +- (nonnull instancetype)initWithSize:(CGSize)size format:(nonnull RCTUIGraphicsImageRendererFormat *)format { + if (self = [super init]) { + self->_size = size; + } + return self; +} + +- (nonnull NSImage *)imageWithActions:(NS_NOESCAPE RCTUIGraphicsImageDrawingActions)actions { + + NSImage *image = [[NSImage alloc] initWithSize:_size]; + [image lockFocusFlipped:YES]; + actions([NSGraphicsContext currentContext]); + [image unlockFocus]; + return image; +} + +@end + #endif diff --git a/packages/react-native/React/Views/RCTBorderDrawing.m b/packages/react-native/React/Views/RCTBorderDrawing.m index 69518c98ec6d13..15401054069b9a 100644 --- a/packages/react-native/React/Views/RCTBorderDrawing.m +++ b/packages/react-native/React/Views/RCTBorderDrawing.m @@ -171,27 +171,16 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn return RCTPathCreateWithRoundedRect(rect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL); } -#if !TARGET_OS_OSX // [macOS] -static UIGraphicsImageRenderer * -RCTUIGraphicsImageRenderer(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge) +static RCTUIGraphicsImageRenderer * // [macOS] +RCTUIGraphicsImageRenderer2(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge) { const CGFloat alpha = CGColorGetAlpha(backgroundColor); const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0; - UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat]; + RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS] rendererFormat.opaque = opaque; - UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:rendererFormat]; + RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:size format:rendererFormat]; // [macOS] return renderer; } -#else // [macOS -static CGContextRef -RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge, CGFloat scaleFactor) -{ - const CGFloat alpha = CGColorGetAlpha(backgroundColor); - const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0; - UIGraphicsBeginImageContextWithOptions(size, opaque, scaleFactor); - return UIGraphicsGetCurrentContext(); -} -#endif // macOS] static UIImage *RCTGetSolidBorderImage( RCTCornerRadii cornerRadii, @@ -237,16 +226,10 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn return nil; } // macOS] -#if !TARGET_OS_OSX // [macOS] - UIGraphicsImageRenderer *const imageRenderer = - RCTUIGraphicsImageRenderer(size, backgroundColor, hasCornerRadii, drawToEdge); - UIImage *image = [imageRenderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) { + RCTUIGraphicsImageRenderer *const imageRenderer = + RCTUIGraphicsImageRenderer2(size, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] + UIImage *image = [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; -#else // [macOS - CGContextRef context = RCTUIGraphicsBeginImageContext(size, backgroundColor, hasCornerRadii, drawToEdge, scaleFactor); - // Add extra braces for scope to match the indentation level of the iOS block - { -#endif // macOS] const CGRect rect = {.size = size}; CGPathRef path = RCTPathCreateOuterOutline(drawToEdge, rect, cornerRadii); @@ -402,13 +385,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn } CGPathRelease(insetPath); -#if !TARGET_OS_OSX // [macOS] }]; -#else // [macOS - } - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); -#endif // macOS] if (makeStretchable) { #if !TARGET_OS_OSX // [macOS] @@ -509,16 +486,10 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn } // macOS] const BOOL hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii); -#if !TARGET_OS_OSX // [macOS] - UIGraphicsImageRenderer *const imageRenderer = - RCTUIGraphicsImageRenderer(viewSize, backgroundColor, hasCornerRadii, drawToEdge); - return [imageRenderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) { + RCTUIGraphicsImageRenderer *const imageRenderer = // [macOS] + RCTUIGraphicsImageRenderer2(viewSize, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] + return [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; -#else // [macOS - CGContextRef context = RCTUIGraphicsBeginImageContext(viewSize, backgroundColor, hasCornerRadii, drawToEdge, scaleFactor); - // Add extra braces for scope to match the indentation level of the iOS block - { -#endif // macOS] const CGRect rect = {.size = viewSize}; if (backgroundColor) { @@ -549,14 +520,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn CGContextStrokePath(context); CGPathRelease(path); -#if !TARGET_OS_OSX // [macOS] }]; -#else // [macOS - } - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return image; -#endif // macOS] } UIImage *RCTGetBorderImage( diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m index 8cdbee6d6c345a..22546e70d5a2f2 100644 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m +++ b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m @@ -16,20 +16,13 @@ - (UIImage *)diffWithImage:(UIImage *)image } CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height)); -#if !TARGET_OS_OSX // [macOS] - UIGraphicsImageRendererFormat *const rendererFormat = [UIGraphicsImageRendererFormat defaultFormat]; + RCTUIGraphicsImageRendererFormat *const rendererFormat = [RCTUIGraphicsImageRendererFormat defaultFormat]; // [macOS] rendererFormat.opaque = YES; - UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize - format:rendererFormat]; + RCTUIGraphicsImageRenderer *const renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:imageSize // [macOS] + format:rendererFormat]; - return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) { + return [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; -#else // [macOS - UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0.0); - CGContextRef context = UIGraphicsGetCurrentContext(); - // Add extra braces for scope to match the indentation level of the iOS block - { -#endif // macOS] [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; CGContextSetAlpha(context, 0.5f); CGContextBeginTransparencyLayer(context, NULL); @@ -38,14 +31,7 @@ - (UIImage *)diffWithImage:(UIImage *)image CGContextSetFillColorWithColor(context, [RCTUIColor whiteColor].CGColor); CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height)); CGContextEndTransparencyLayer(context); -#if !TARGET_OS_OSX // [macOS] }]; -#else // [macOS - } - UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return returnImage; -#endif // macOS] } @end From 7e422d7b635718365a7f7d6d9f6a78636ce1d110 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 1 Oct 2024 23:12:39 -0500 Subject: [PATCH 2/6] Update RCTBorderDrawing.m --- packages/react-native/React/Views/RCTBorderDrawing.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-native/React/Views/RCTBorderDrawing.m b/packages/react-native/React/Views/RCTBorderDrawing.m index 15401054069b9a..a464a10a4634f8 100644 --- a/packages/react-native/React/Views/RCTBorderDrawing.m +++ b/packages/react-native/React/Views/RCTBorderDrawing.m @@ -172,7 +172,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn } static RCTUIGraphicsImageRenderer * // [macOS] -RCTUIGraphicsImageRenderer2(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge) +RCTMakeUIGraphicsImageRenderer(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge) // [macOS] { const CGFloat alpha = CGColorGetAlpha(backgroundColor); const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0; @@ -227,7 +227,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn } // macOS] RCTUIGraphicsImageRenderer *const imageRenderer = - RCTUIGraphicsImageRenderer2(size, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] + RCTMakeUIGraphicsImageRenderer(size, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] UIImage *image = [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; const CGRect rect = {.size = size}; @@ -487,7 +487,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn const BOOL hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii); RCTUIGraphicsImageRenderer *const imageRenderer = // [macOS] - RCTUIGraphicsImageRenderer2(viewSize, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] + RCTMakeUIGraphicsImageRenderer(viewSize, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] return [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; const CGRect rect = {.size = viewSize}; From 67915e7e38e96f5ba84ca81282ef4809d1d546ec Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 2 Oct 2024 14:39:09 -0500 Subject: [PATCH 3/6] `[RCTUIGraphicsImageRendererFormat defaultFormat]` doesn't return a singleton --- packages/react-native/React/Base/macOS/RCTUIKit.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/react-native/React/Base/macOS/RCTUIKit.m b/packages/react-native/React/Base/macOS/RCTUIKit.m index c55d39a2ae2958..577e1a6bb2ddd9 100644 --- a/packages/react-native/React/Base/macOS/RCTUIKit.m +++ b/packages/react-native/React/Base/macOS/RCTUIKit.m @@ -1006,12 +1006,8 @@ - (void)setImage:(UIImage *)image @implementation RCTUIGraphicsImageRendererFormat + (nonnull instancetype)defaultFormat { - static dispatch_once_t token = 0; - static RCTUIGraphicsImageRendererFormat *_sharedObject = nil; - dispatch_once(&token, ^{ - _sharedObject = [[self alloc] init]; - }); - return _sharedObject; + RCTUIGraphicsImageRendererFormat *format = [RCTUIGraphicsImageRendererFormat new]; + return format; } @end @@ -1019,11 +1015,13 @@ + (nonnull instancetype)defaultFormat { @implementation RCTUIGraphicsImageRenderer { CGSize _size; + RCTUIGraphicsImageRendererFormat *_format; } - (nonnull instancetype)initWithSize:(CGSize)size format:(nonnull RCTUIGraphicsImageRendererFormat *)format { if (self = [super init]) { self->_size = size; + self->_format = format; } return self; } From 9ee5e1f3c5219817c0e09962666bc696e20bb47d Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 2 Oct 2024 15:51:21 -0500 Subject: [PATCH 4/6] `[NSImage lockFocus]` is deprecated. Use a newer API. --- packages/react-native/React/Base/macOS/RCTUIKit.m | 10 ++++++---- packages/react-native/React/Views/RCTBorderDrawing.m | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/react-native/React/Base/macOS/RCTUIKit.m b/packages/react-native/React/Base/macOS/RCTUIKit.m index 577e1a6bb2ddd9..698585146123a0 100644 --- a/packages/react-native/React/Base/macOS/RCTUIKit.m +++ b/packages/react-native/React/Base/macOS/RCTUIKit.m @@ -1028,10 +1028,12 @@ - (nonnull instancetype)initWithSize:(CGSize)size format:(nonnull RCTUIGraphicsI - (nonnull NSImage *)imageWithActions:(NS_NOESCAPE RCTUIGraphicsImageDrawingActions)actions { - NSImage *image = [[NSImage alloc] initWithSize:_size]; - [image lockFocusFlipped:YES]; - actions([NSGraphicsContext currentContext]); - [image unlockFocus]; + NSImage *image = [NSImage imageWithSize:_size + flipped:YES + drawingHandler:^BOOL(NSRect dstRect) { + actions([NSGraphicsContext currentContext]); + return YES; + }]; return image; } diff --git a/packages/react-native/React/Views/RCTBorderDrawing.m b/packages/react-native/React/Views/RCTBorderDrawing.m index a464a10a4634f8..ba8a11009315c8 100644 --- a/packages/react-native/React/Views/RCTBorderDrawing.m +++ b/packages/react-native/React/Views/RCTBorderDrawing.m @@ -228,6 +228,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn RCTUIGraphicsImageRenderer *const imageRenderer = RCTMakeUIGraphicsImageRenderer(size, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] + CGColorRetain(backgroundColor); // [macOS] CGColorRefs are not atuomtically retained wehn passed into a block UIImage *image = [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; const CGRect rect = {.size = size}; @@ -238,6 +239,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn CGContextAddPath(context, path); CGContextFillPath(context); } + CGColorRelease(backgroundColor); // [macOS] CGContextAddPath(context, path); CGPathRelease(path); From 7b77411709d1dd947cac416f87f50cb6098848c9 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 2 Oct 2024 23:37:25 -0500 Subject: [PATCH 5/6] fix typo --- packages/react-native/React/Views/RCTBorderDrawing.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/React/Views/RCTBorderDrawing.m b/packages/react-native/React/Views/RCTBorderDrawing.m index ba8a11009315c8..6fb3f7b5519513 100644 --- a/packages/react-native/React/Views/RCTBorderDrawing.m +++ b/packages/react-native/React/Views/RCTBorderDrawing.m @@ -228,7 +228,7 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn RCTUIGraphicsImageRenderer *const imageRenderer = RCTMakeUIGraphicsImageRenderer(size, backgroundColor, hasCornerRadii, drawToEdge); // [macOS] - CGColorRetain(backgroundColor); // [macOS] CGColorRefs are not atuomtically retained wehn passed into a block + CGColorRetain(backgroundColor); // [macOS] CGColorRefs are not atuomtically retained when passed into a block UIImage *image = [imageRenderer imageWithActions:^(RCTUIGraphicsImageRendererContext *_Nonnull rendererContext) { // [macOS] const CGContextRef context = rendererContext.CGContext; const CGRect rect = {.size = size}; From e5e1600c6a8ba15c053c19771a94c102bb6b0f95 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 3 Oct 2024 15:23:51 -0500 Subject: [PATCH 6/6] Implement `format.opaque` --- packages/react-native/React/Base/macOS/RCTUIKit.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-native/React/Base/macOS/RCTUIKit.m b/packages/react-native/React/Base/macOS/RCTUIKit.m index 698585146123a0..48f2ec5f8eff5c 100644 --- a/packages/react-native/React/Base/macOS/RCTUIKit.m +++ b/packages/react-native/React/Base/macOS/RCTUIKit.m @@ -1031,7 +1031,12 @@ - (nonnull NSImage *)imageWithActions:(NS_NOESCAPE RCTUIGraphicsImageDrawingActi NSImage *image = [NSImage imageWithSize:_size flipped:YES drawingHandler:^BOOL(NSRect dstRect) { - actions([NSGraphicsContext currentContext]); + + RCTUIGraphicsImageRendererContext *context = [NSGraphicsContext currentContext]; + if (self->_format.opaque) { + CGContextSetAlpha([context CGContext], 1.0); + } + actions(context); return YES; }]; return image;